From 02f31ac96e9a079e2305188423b64475c6b3be79 Mon Sep 17 00:00:00 2001 From: Abdellatif Ait boudad Date: Mon, 14 Aug 2017 11:38:08 +0100 Subject: [PATCH 001/499] [Translation] create custom message formatter. --- components/translation.rst | 3 +- .../translation/custom_message_formatter.rst | 55 +++++++++++++++++++ reference/configuration/framework.rst | 15 +++++ 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 components/translation/custom_message_formatter.rst diff --git a/components/translation.rst b/components/translation.rst index dfbf9fd6259..30b69797414 100644 --- a/components/translation.rst +++ b/components/translation.rst @@ -34,9 +34,8 @@ The constructor of the ``Translator`` class needs one argument: The locale. .. code-block:: php use Symfony\Component\Translation\Translator; - use Symfony\Component\Translation\MessageSelector; - $translator = new Translator('fr_FR', new MessageSelector()); + $translator = new Translator('fr_FR'); .. note:: diff --git a/components/translation/custom_message_formatter.rst b/components/translation/custom_message_formatter.rst new file mode 100644 index 00000000000..22a650ea23c --- /dev/null +++ b/components/translation/custom_message_formatter.rst @@ -0,0 +1,55 @@ +.. index:: + single: Translation; Create Custom Message formatter + +Create Custom Message Formatter +=============================== + +The default Message Formatter provide a simple and easy way that deals with the most common use-cases +such as message placeholders and pluralization. But in some cases, you may want to use a custom message formatter +that fit to your specific needs, for example, handle nested conditions of pluralization or select sub-messages +via a fixed set of keywords (e.g. gender). + +Suppose in your application you want to displays different text depending on arbitrary conditions, +for example upon whether the guest is male or female. To do this, we will use the `ICU Message Format`_ +which the most suitable ones you first need to create a `IntlMessageFormatter` and pass it to the `Translator`. + +.. _components-translation-message-formatter: + +Creating a Custom Message Formatter +----------------------------------- + +To define a custom message formatter that is able to read these kinds of rules, you must create a +new class that implements the +:class:`Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface`:: + + use Symfony\Component\Translation\Formatter\MessageFormatterInterface; + + class IntlMessageFormatter implements MessageFormatterInterface + { + public function format($message, $locale, array $parameters = array()) + { + $formatter = new \MessageFormatter($locale, $message); + if (null === $formatter) { + throw new \InvalidArgumentException(sprintf('Invalid message format. Reason: %s (error #%d)', intl_get_error_message(), intl_get_error_code())); + } + + $message = $formatter->format($parameters); + if ($formatter->getErrorCode() !== U_ZERO_ERROR) { + throw new \InvalidArgumentException(sprintf('Unable to format message. Reason: %s (error #%s)', $formatter->getErrorMessage(), $formatter->getErrorCode())); + } + + return $message; + } + } + +Once created, simply pass it as the second argument to the `Translator`:: + + use Symfony\Component\Translation\Translator; + + $translator = new Translator('fr_FR', new IntlMessageFormatter()); + + var_dump($translator->trans('The guest is {gender, select, m {male} f {female}}', [ 'gender' => 'm' ])); + +It will print *"The guest is male"*. + +.. _`ICU Message Format`: http://userguide.icu-project.org/formatparse/messages diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 50c5ac2cde0..5cc0aa04b4d 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -85,6 +85,7 @@ Configuration * :ref:`enabled ` * `fallbacks`_ * `logging`_ + * `formatter`_ * :ref:`paths ` * `property_access`_ * `magic_call`_ @@ -1481,6 +1482,20 @@ 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. +.. _reference-framework-translator-formatter: + +formatter +......... + +**type**: ``string`` **default**: ``translator.formatter.default`` + +The service that is used to format message. The service +has to implement the :class:`Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface`. + +.. seealso:: + + For more details, see :doc:`/components/translation/custom_message_formatter`. + .. _reference-translator-paths: paths From 6e2f04a313944473d47d222164ea4c95230f27c0 Mon Sep 17 00:00:00 2001 From: Titouan Galopin Date: Sat, 24 Nov 2018 15:17:38 +0100 Subject: [PATCH 002/499] [DomCrawler] Add note about the HTML5 parser library --- components/dom_crawler.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index 60f6cb5186e..8901ebd53e9 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -72,6 +72,13 @@ tree. isn't meant to dump content, you can see the "fixed" version of your HTML by :ref:`dumping it `. +.. note:: + + When available, the DomCrawler will use the + [html5-php library](https://github.com/Masterminds/html5-php) to parse HTML content. + If you need to support specific HTML5 tags ou if you are getting unexpected behaviors + using the DomCrawler, you can install the library to fix the problem. + Node Filtering ~~~~~~~~~~~~~~ From 8e44f8e909a68921f119192c8771e5c05b96179c Mon Sep 17 00:00:00 2001 From: Anthony MARTIN Date: Wed, 30 Jan 2019 11:46:12 +0100 Subject: [PATCH 003/499] Update the documentation for the PR #30027 --- reference/configuration/framework.rst | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 83325d3e26d..bcfafe97ba3 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -152,6 +152,8 @@ Configuration * `metadata_update_threshold`_ * `name`_ * `save_path`_ + * `sid_length`_ + * `sid_bits_per_character`_ * `storage_id`_ * `templating`_ @@ -899,6 +901,31 @@ This determines the number of seconds after which data will be seen as "garbage" and potentially cleaned up. Garbage collection may occur during session start and depends on `gc_divisor`_ and `gc_probability`_. +sid_length +.......... + +**type**: ``integer`` + +This determines the length of session ID string. Session ID length can be +between 22 to 256. The default is 32. If you need compatibility you may +specify 32, 40, etc. Longer session ID is harder to guess. At least 32 chars +is recommended. + +This option refers to the`session.sid_length` of the `php.ini` + +sid_bits_per_character +...................... + +**type**: ``integer`` + +This determines the number of bits in encoded session ID character. +The possible values are '4' (0-9, a-f), '5' (0-9, a-v), and '6' +(0-9, a-z, A-Z, "-", ","). +The default is 4. The more bits results in stronger session ID. +5 is recommended value for most environments. + +This option refers to the`session.sid_bits_per_character` of the `php.ini` + save_path ......... From cc6a5f30beef994adf0de13510be5edcc49d15ee Mon Sep 17 00:00:00 2001 From: Mathieu Piot Date: Sun, 10 Feb 2019 16:44:52 +0100 Subject: [PATCH 004/499] Add help_html --- reference/forms/types/birthday.rst | 3 +++ reference/forms/types/checkbox.rst | 3 +++ reference/forms/types/choice.rst | 3 +++ reference/forms/types/collection.rst | 3 +++ reference/forms/types/color.rst | 3 +++ reference/forms/types/country.rst | 3 +++ reference/forms/types/currency.rst | 3 +++ reference/forms/types/date.rst | 3 +++ reference/forms/types/dateinterval.rst | 3 +++ reference/forms/types/datetime.rst | 3 +++ reference/forms/types/email.rst | 3 +++ reference/forms/types/entity.rst | 3 +++ reference/forms/types/file.rst | 3 +++ reference/forms/types/form.rst | 3 +++ reference/forms/types/integer.rst | 3 +++ reference/forms/types/language.rst | 3 +++ reference/forms/types/locale.rst | 3 +++ reference/forms/types/money.rst | 3 +++ reference/forms/types/number.rst | 3 +++ reference/forms/types/options/help_html.rst.inc | 7 +++++++ reference/forms/types/password.rst | 3 +++ reference/forms/types/percent.rst | 3 +++ reference/forms/types/radio.rst | 3 +++ reference/forms/types/range.rst | 3 +++ reference/forms/types/repeated.rst | 3 +++ reference/forms/types/search.rst | 3 +++ reference/forms/types/tel.rst | 3 +++ reference/forms/types/text.rst | 3 +++ reference/forms/types/textarea.rst | 3 +++ reference/forms/types/time.rst | 3 +++ reference/forms/types/timezone.rst | 3 +++ reference/forms/types/url.rst | 3 +++ 32 files changed, 100 insertions(+) create mode 100644 reference/forms/types/options/help_html.rst.inc diff --git a/reference/forms/types/birthday.rst b/reference/forms/types/birthday.rst index 3136ed8cdf9..04fa1868f3d 100644 --- a/reference/forms/types/birthday.rst +++ b/reference/forms/types/birthday.rst @@ -40,6 +40,7 @@ option defaults to 120 years ago to the current year. | | - `disabled`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `inherit_data`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | @@ -116,6 +117,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/help_attr.rst.inc +.. include:: /reference/forms/types/options/help_html.rst.inc + .. include:: /reference/forms/types/options/inherit_data.rst.inc .. include:: /reference/forms/types/options/invalid_message.rst.inc diff --git a/reference/forms/types/checkbox.rst b/reference/forms/types/checkbox.rst index 9814e0306db..e5b23ab68a1 100644 --- a/reference/forms/types/checkbox.rst +++ b/reference/forms/types/checkbox.rst @@ -26,6 +26,7 @@ if you want to handle submitted values like "0" or "false"). | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -88,6 +89,8 @@ These options inherit from the :doc:`FormType `: .. 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 diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index 6c7dd1ce8ec..13f0c0bdcdb 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -37,6 +37,7 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `inherit_data`_ | | | - `label`_ | | | - `label_attr`_ | @@ -280,6 +281,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/help_attr.rst.inc +.. include:: /reference/forms/types/options/help_html.rst.inc + .. include:: /reference/forms/types/options/inherit_data.rst.inc .. include:: /reference/forms/types/options/label.rst.inc diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst index e451791be51..eb4ddcdb64a 100644 --- a/reference/forms/types/collection.rst +++ b/reference/forms/types/collection.rst @@ -29,6 +29,7 @@ photos). | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -426,6 +427,8 @@ error_bubbling .. 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 diff --git a/reference/forms/types/color.rst b/reference/forms/types/color.rst index db8c5f0365f..e601f1e6932 100644 --- a/reference/forms/types/color.rst +++ b/reference/forms/types/color.rst @@ -24,6 +24,7 @@ element. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -63,6 +64,8 @@ The default value is ``''`` (the empty string). .. 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 diff --git a/reference/forms/types/country.rst b/reference/forms/types/country.rst index ed51d8c023e..423d49e4224 100644 --- a/reference/forms/types/country.rst +++ b/reference/forms/types/country.rst @@ -43,6 +43,7 @@ the option manually, but then you should just use the ``ChoiceType`` directly. | | - `empty_data`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -118,6 +119,8 @@ The actual default value of this option depends on other field options: .. 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 diff --git a/reference/forms/types/currency.rst b/reference/forms/types/currency.rst index 0392bd72d48..15f94ec5b6b 100644 --- a/reference/forms/types/currency.rst +++ b/reference/forms/types/currency.rst @@ -35,6 +35,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `empty_data`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -107,6 +108,8 @@ The actual default value of this option depends on other field options: .. 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 diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index 3ed4afdba96..0b240504c17 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -37,6 +37,7 @@ and can understand a number of different input formats via the `input`_ option. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `inherit_data`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | @@ -214,6 +215,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/help_attr.rst.inc +.. include:: /reference/forms/types/options/help_html.rst.inc + .. include:: /reference/forms/types/options/inherit_data.rst.inc .. include:: /reference/forms/types/options/invalid_message.rst.inc diff --git a/reference/forms/types/dateinterval.rst b/reference/forms/types/dateinterval.rst index 814aa18f77d..e9a3539b0d8 100644 --- a/reference/forms/types/dateinterval.rst +++ b/reference/forms/types/dateinterval.rst @@ -41,6 +41,7 @@ or an array (see `input`_). | options | - `disabled`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `inherit_data`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | @@ -315,6 +316,8 @@ These options inherit from the :doc:`form ` type: .. include:: /reference/forms/types/options/help_attr.rst.inc +.. include:: /reference/forms/types/options/help_html.rst.inc + .. include:: /reference/forms/types/options/inherit_data.rst.inc .. include:: /reference/forms/types/options/invalid_message.rst.inc diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index e3ce3f12586..5b9295c5885 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -46,6 +46,7 @@ the data can be a ``DateTime`` object, a string, a timestamp or an array. | options | - `disabled`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `inherit_data`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | @@ -233,6 +234,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/help_attr.rst.inc +.. include:: /reference/forms/types/options/help_html.rst.inc + .. include:: /reference/forms/types/options/inherit_data.rst.inc .. include:: /reference/forms/types/options/invalid_message.rst.inc diff --git a/reference/forms/types/email.rst b/reference/forms/types/email.rst index 471f87137c0..6e698caf1d6 100644 --- a/reference/forms/types/email.rst +++ b/reference/forms/types/email.rst @@ -17,6 +17,7 @@ The ``EmailType`` field is a text field that is rendered using the HTML5 | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -56,6 +57,8 @@ The default value is ``''`` (the empty string). .. 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 diff --git a/reference/forms/types/entity.rst b/reference/forms/types/entity.rst index e99c75b65be..034e1cafb84 100644 --- a/reference/forms/types/entity.rst +++ b/reference/forms/types/entity.rst @@ -43,6 +43,7 @@ objects from the database. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -335,6 +336,8 @@ The actual default value of this option depends on other field options: .. 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 diff --git a/reference/forms/types/file.rst b/reference/forms/types/file.rst index e28b52de4d7..9c9c892a98c 100644 --- a/reference/forms/types/file.rst +++ b/reference/forms/types/file.rst @@ -20,6 +20,7 @@ The ``FileType`` represents a file input in your form. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -132,6 +133,8 @@ These options inherit from the :doc:`FormType `: .. 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 diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index 3edb88667ef..d31f75126ec 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -21,6 +21,7 @@ on all types for which ``FormType`` is the parent. | | - `extra_fields_message`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `inherit_data`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | @@ -110,6 +111,8 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/help_attr.rst.inc +.. include:: /reference/forms/types/options/help_html.rst.inc + .. include:: /reference/forms/types/options/inherit_data.rst.inc .. include:: /reference/forms/types/options/invalid_message.rst.inc diff --git a/reference/forms/types/integer.rst b/reference/forms/types/integer.rst index 1c35c581f08..70968886016 100644 --- a/reference/forms/types/integer.rst +++ b/reference/forms/types/integer.rst @@ -29,6 +29,7 @@ integers. By default, all non-integer values (e.g. 6.78) will round down | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `label`_ | @@ -118,6 +119,8 @@ The default value is ``''`` (the empty string). .. 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.rst.inc .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc diff --git a/reference/forms/types/language.rst b/reference/forms/types/language.rst index 244cea352b5..013dbbb7430 100644 --- a/reference/forms/types/language.rst +++ b/reference/forms/types/language.rst @@ -45,6 +45,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `empty_data`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -120,6 +121,8 @@ The actual default value of this option depends on other field options: .. 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 diff --git a/reference/forms/types/locale.rst b/reference/forms/types/locale.rst index dca67366178..bfe19e9e2c8 100644 --- a/reference/forms/types/locale.rst +++ b/reference/forms/types/locale.rst @@ -46,6 +46,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `empty_data`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -121,6 +122,8 @@ The actual default value of this option depends on other field options: .. 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 diff --git a/reference/forms/types/money.rst b/reference/forms/types/money.rst index dafa34543e2..a02b68b95a7 100644 --- a/reference/forms/types/money.rst +++ b/reference/forms/types/money.rst @@ -30,6 +30,7 @@ how the input and output of the data is handled. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `label`_ | @@ -126,6 +127,8 @@ The default value is ``''`` (the empty string). .. 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.rst.inc .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc diff --git a/reference/forms/types/number.rst b/reference/forms/types/number.rst index 0726f0a971d..4d77428e171 100644 --- a/reference/forms/types/number.rst +++ b/reference/forms/types/number.rst @@ -25,6 +25,7 @@ that you want to use for your number. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `label`_ | @@ -87,6 +88,8 @@ The default value is ``''`` (the empty string). .. 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.rst.inc .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc diff --git a/reference/forms/types/options/help_html.rst.inc b/reference/forms/types/options/help_html.rst.inc new file mode 100644 index 00000000000..d53c4ed49e2 --- /dev/null +++ b/reference/forms/types/options/help_html.rst.inc @@ -0,0 +1,7 @@ +help_html +~~~~~~~~~ + +**type**: ``bool`` **default**: ``false`` + +Define if the help content will be escaped when rendered or not. Default is `false`, +the HTML content is escaped. Set it to true if you want to use HTML help message. diff --git a/reference/forms/types/password.rst b/reference/forms/types/password.rst index ecf209757c1..47004089d01 100644 --- a/reference/forms/types/password.rst +++ b/reference/forms/types/password.rst @@ -20,6 +20,7 @@ The ``PasswordType`` field renders an input password text box. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -85,6 +86,8 @@ The default value is ``''`` (the empty string). .. 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 diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index b4bba6f12fc..3485fb52766 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -27,6 +27,7 @@ This field adds a percentage sign "``%``" after the input box. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `label`_ | @@ -103,6 +104,8 @@ The default value is ``''`` (the empty string). .. 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.rst.inc .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc diff --git a/reference/forms/types/radio.rst b/reference/forms/types/radio.rst index 74a0d461702..868168be35f 100644 --- a/reference/forms/types/radio.rst +++ b/reference/forms/types/radio.rst @@ -29,6 +29,7 @@ If you want to have a boolean field, use :doc:`CheckboxType `: .. 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 diff --git a/reference/forms/types/range.rst b/reference/forms/types/range.rst index 2d0a094e34d..bed09c510ca 100644 --- a/reference/forms/types/range.rst +++ b/reference/forms/types/range.rst @@ -18,6 +18,7 @@ The ``RangeType`` field is a slider that is rendered using the HTML5 | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `mapped`_ | @@ -73,6 +74,8 @@ The default value is ``''`` (the empty string). .. 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 diff --git a/reference/forms/types/repeated.rst b/reference/forms/types/repeated.rst index d1f8fe128a0..4c0aba2d7ff 100644 --- a/reference/forms/types/repeated.rst +++ b/reference/forms/types/repeated.rst @@ -26,6 +26,7 @@ accuracy. | options | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | | | - `mapped`_ | @@ -189,6 +190,8 @@ These options inherit from the :doc:`FormType `: .. 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.rst.inc .. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc diff --git a/reference/forms/types/search.rst b/reference/forms/types/search.rst index c3e7e2db0d2..92bbc750f2a 100644 --- a/reference/forms/types/search.rst +++ b/reference/forms/types/search.rst @@ -18,6 +18,7 @@ Read about the input search field at `DiveIntoHTML5.info`_ | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -55,6 +56,8 @@ The default value is ``''`` (the empty string). .. 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 diff --git a/reference/forms/types/tel.rst b/reference/forms/types/tel.rst index fa56a941ffb..73007d70c5e 100644 --- a/reference/forms/types/tel.rst +++ b/reference/forms/types/tel.rst @@ -23,6 +23,7 @@ to input phone numbers. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -62,6 +63,8 @@ The default value is ``''`` (the empty string). .. 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 diff --git a/reference/forms/types/text.rst b/reference/forms/types/text.rst index cfd4c608464..7dc5ddf5554 100644 --- a/reference/forms/types/text.rst +++ b/reference/forms/types/text.rst @@ -17,6 +17,7 @@ The TextType field represents the most basic input text field. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -63,6 +64,8 @@ an empty string, explicitly set the ``empty_data`` option to an empty string. .. 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 diff --git a/reference/forms/types/textarea.rst b/reference/forms/types/textarea.rst index 6b0a7c502ba..5e0f70d967a 100644 --- a/reference/forms/types/textarea.rst +++ b/reference/forms/types/textarea.rst @@ -17,6 +17,7 @@ Renders a ``textarea`` HTML element. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -64,6 +65,8 @@ The default value is ``''`` (the empty string). .. 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 diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst index 0181f0ea75f..50b7ac86f77 100644 --- a/reference/forms/types/time.rst +++ b/reference/forms/types/time.rst @@ -38,6 +38,7 @@ stored as a ``DateTime`` object, a string, a timestamp or an array. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `inherit_data`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | @@ -201,6 +202,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/help_attr.rst.inc +.. include:: /reference/forms/types/options/help_html.rst.inc + .. include:: /reference/forms/types/options/inherit_data.rst.inc .. include:: /reference/forms/types/options/invalid_message.rst.inc diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst index b190edb430e..c486bcd497c 100644 --- a/reference/forms/types/timezone.rst +++ b/reference/forms/types/timezone.rst @@ -40,6 +40,7 @@ manually, but then you should just use the ``ChoiceType`` directly. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -135,6 +136,8 @@ The actual default value of this option depends on other field options: .. 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 diff --git a/reference/forms/types/url.rst b/reference/forms/types/url.rst index b4cd95758ad..d9246467633 100644 --- a/reference/forms/types/url.rst +++ b/reference/forms/types/url.rst @@ -20,6 +20,7 @@ have a protocol. | | - `error_mapping`_ | | | - `help`_ | | | - `help_attr`_ | +| | - `help_html`_ | | | - `label`_ | | | - `label_attr`_ | | | - `label_format`_ | @@ -71,6 +72,8 @@ The default value is ``''`` (the empty string). .. 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 From 9f23a815f67352d00a82d32510d0607f27799f03 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 11 Feb 2019 10:03:46 +0100 Subject: [PATCH 005/499] Minor reword --- reference/forms/types/options/help_html.rst.inc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/reference/forms/types/options/help_html.rst.inc b/reference/forms/types/options/help_html.rst.inc index d53c4ed49e2..83bbe583ca6 100644 --- a/reference/forms/types/options/help_html.rst.inc +++ b/reference/forms/types/options/help_html.rst.inc @@ -3,5 +3,6 @@ help_html **type**: ``bool`` **default**: ``false`` -Define if the help content will be escaped when rendered or not. Default is `false`, -the HTML content is escaped. Set it to true if you want to use HTML help message. +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 +useful when the help contains HTML elements. From 927dee1fc96275aa7de384de07257db6097eb4b3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 11 Feb 2019 12:06:55 +0100 Subject: [PATCH 006/499] Minor reword --- reference/configuration/framework.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index bcfafe97ba3..bb154f8e2e7 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -904,27 +904,25 @@ start and depends on `gc_divisor`_ and `gc_probability`_. sid_length .......... -**type**: ``integer`` +**type**: ``integer`` **default**: ``32`` -This determines the length of session ID string. Session ID length can be -between 22 to 256. The default is 32. If you need compatibility you may -specify 32, 40, etc. Longer session ID is harder to guess. At least 32 chars -is recommended. +This determines the length of session ID string, which can be an integer between +``22`` and ``256`` (both inclusive), being ``32`` the recommended value. Longer +session IDs are harder to guess. -This option refers to the`session.sid_length` of the `php.ini` +This option is related to the `session.sid_length PHP option`_. sid_bits_per_character ...................... -**type**: ``integer`` +**type**: ``integer`` **default**: ``4`` -This determines the number of bits in encoded session ID character. -The possible values are '4' (0-9, a-f), '5' (0-9, a-v), and '6' -(0-9, a-z, A-Z, "-", ","). -The default is 4. The more bits results in stronger session ID. -5 is recommended value for most environments. +This determines the number of bits in encoded session ID character. The possible +values are ``4`` (0-9, a-f), ``5`` (0-9, a-v), and ``6`` (0-9, a-z, A-Z, "-", ","). +The more bits results in stronger session ID. ``5`` is recommended value for +most environments. -This option refers to the`session.sid_bits_per_character` of the `php.ini` +This option is related to the `session.sid_bits_per_character PHP option`_. save_path ......... @@ -2178,3 +2176,5 @@ available, or to ``flock`` otherwise. Store's DSN are also allowed. .. _`webpack-manifest-plugin`: https://www.npmjs.com/package/webpack-manifest-plugin .. _`error_reporting PHP option`: https://secure.php.net/manual/en/errorfunc.configuration.php#ini.error-reporting .. _`CSRF security attacks`: https://en.wikipedia.org/wiki/Cross-site_request_forgery +.. _`session.sid_length PHP option`: https://php.net/manual/session.configuration.php#ini.session.sid-length +.. _`session.sid_bits_per_character PHP option`: https://php.net/manual/session.configuration.php#ini.session.sid-bits-per-character From 89f02960cfae07d978c06cb22b30bbbfc8890091 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 11 Feb 2019 12:26:50 +0100 Subject: [PATCH 007/499] Added a note about the deprecations of DateTimeType --- reference/forms/types/datetime.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index 5b9295c5885..36364885553 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -196,6 +196,11 @@ Defines the ``widget`` option for both the :doc:`DateType `. This can be overridden with the `date_widget`_ and `time_widget`_ options. +.. versionadded:: 4.3 + + Using the ``date_format``, ``date_widget``, and ``time_widget`` options when + the ``widget`` option is set to ``single_text`` is deprecated since Symfony 4.3. + .. include:: /reference/forms/types/options/with_minutes.rst.inc .. include:: /reference/forms/types/options/with_seconds.rst.inc From c57d30af258cfa8290ea58afd50fe584316be78b Mon Sep 17 00:00:00 2001 From: Webnet team Date: Fri, 13 Jul 2018 15:46:49 +0200 Subject: [PATCH 008/499] new translation_parameters form option --- reference/forms/types/button.rst | 3 + reference/forms/types/choice.rst | 3 + reference/forms/types/entity.rst | 3 + reference/forms/types/form.rst | 3 + .../button_translation_parameters.rst.inc | 54 ++++++++++++++++++ .../choice_type_translation_domain.rst.inc | 2 +- ...choice_type_translation_parameters.rst.inc | 56 +++++++++++++++++++ ...entity_type_translation_parameters.rst.inc | 56 +++++++++++++++++++ .../reset_translation_parameters.rst.inc | 54 ++++++++++++++++++ .../submit_translation_parameters.rst.inc | 54 ++++++++++++++++++ .../options/translation_parameters.rst.inc | 49 ++++++++++++++++ reference/forms/types/reset.rst | 3 + reference/forms/types/submit.rst | 3 + templating/PHP.rst | 2 +- 14 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 reference/forms/types/options/button_translation_parameters.rst.inc create mode 100644 reference/forms/types/options/choice_type_translation_parameters.rst.inc create mode 100644 reference/forms/types/options/entity_type_translation_parameters.rst.inc create mode 100644 reference/forms/types/options/reset_translation_parameters.rst.inc create mode 100644 reference/forms/types/options/submit_translation_parameters.rst.inc create mode 100644 reference/forms/types/options/translation_parameters.rst.inc diff --git a/reference/forms/types/button.rst b/reference/forms/types/button.rst index 8ecd99a8a7a..4d84f397267 100644 --- a/reference/forms/types/button.rst +++ b/reference/forms/types/button.rst @@ -13,6 +13,7 @@ A simple, non-responsive button. | options | - `disabled`_ | | | - `label`_ | | | - `translation_domain`_ | +| | - `translation_parameters`_ | +----------------------+----------------------------------------------------------------------+ | Parent type | none | +----------------------+----------------------------------------------------------------------+ @@ -51,3 +52,5 @@ as a key. This can be useful when you need to set a custom class for the button: .. include:: /reference/forms/types/options/button_label.rst.inc .. include:: /reference/forms/types/options/button_translation_domain.rst.inc + +.. include:: /reference/forms/types/options/button_translation_parameters.rst.inc diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index 13f0c0bdcdb..ad47316b948 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -45,6 +45,7 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | | - `mapped`_ | | | - `required`_ | | | - `translation_domain`_ | +| | - `translation_parameters`_ | +-------------+------------------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +-------------+------------------------------------------------------------------------------+ @@ -297,6 +298,8 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/choice_type_translation_domain.rst.inc +.. include:: /reference/forms/types/options/choice_type_translation_parameters.rst.inc + Field Variables --------------- diff --git a/reference/forms/types/entity.rst b/reference/forms/types/entity.rst index 034e1cafb84..db645c3f9a8 100644 --- a/reference/forms/types/entity.rst +++ b/reference/forms/types/entity.rst @@ -32,6 +32,7 @@ objects from the database. | | - `placeholder`_ | | | - `preferred_choices`_ | | | - `translation_domain`_ | +| | - `translation_parameters`_ | | | - `trim`_ | | | | | | from the :doc:`FormType `: | @@ -307,6 +308,8 @@ when rendering the field: .. include:: /reference/forms/types/options/choice_type_translation_domain.rst.inc +.. include:: /reference/forms/types/options/entity_type_translation_parameters.rst.inc + .. include:: /reference/forms/types/options/choice_type_trim.rst.inc These options inherit from the :doc:`form ` diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index d31f75126ec..45e4d3c841b 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -42,6 +42,7 @@ on all types for which ``FormType`` is the parent. | | - `disabled`_ | | | - `label`_ | | | - `translation_domain`_ | +| | - `translation_parameters`_ | +-----------+--------------------------------------------------------------------+ | Parent | none | +-----------+--------------------------------------------------------------------+ @@ -167,3 +168,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.rst.inc .. include:: /reference/forms/types/options/translation_domain.rst.inc + +.. include:: /reference/forms/types/options/translation_parameters.rst.inc diff --git a/reference/forms/types/options/button_translation_parameters.rst.inc b/reference/forms/types/options/button_translation_parameters.rst.inc new file mode 100644 index 00000000000..81c2a44838e --- /dev/null +++ b/reference/forms/types/options/button_translation_parameters.rst.inc @@ -0,0 +1,54 @@ +translation_parameters +~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_ can contain +:ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order_list.submit_to_company: Send an order to %company% + +you can specify placeholder value: + +.. code-block:: php + + use Symfony\Component\Form\Extension\Core\Type\ButtonType; + // ... + + $builder->add('send', ButtonType::class, array( + 'label' => 'form.order_list.submit_to_company', + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +Note that `translation_parameters` of buttons are merged with those of parent. +In other words the parent's parameters are available for buttons but can be +overriden: + +.. code-block:: php + + // App\Controller\OrderListController + + $form = $this->createForm(OrderListType::class, null, array( + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +.. code-block:: php + + // App\Form\OrderListType + use Symfony\Component\Form\Extension\Core\Type\ButtonType; + // ... + + $builder->add('send', ButtonType::class, array( + 'label' => 'form.order_list.submit_to_company', + )); diff --git a/reference/forms/types/options/choice_type_translation_domain.rst.inc b/reference/forms/types/options/choice_type_translation_domain.rst.inc index 87cd76cff9a..c22125ea844 100644 --- a/reference/forms/types/options/choice_type_translation_domain.rst.inc +++ b/reference/forms/types/options/choice_type_translation_domain.rst.inc @@ -5,4 +5,4 @@ translation_domain In case `choice_translation_domain`_ is set to ``true`` or ``null``, this configures the exact translation domain that will be used for any labels or -options that are rendered for this field +options that are rendered for this field. diff --git a/reference/forms/types/options/choice_type_translation_parameters.rst.inc b/reference/forms/types/options/choice_type_translation_parameters.rst.inc new file mode 100644 index 00000000000..6425dbca3c8 --- /dev/null +++ b/reference/forms/types/options/choice_type_translation_parameters.rst.inc @@ -0,0 +1,56 @@ +translation_parameters +~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_, `help`_ and some attr_ (``title``, ``placeholder``) can +contain :ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order_list.notify: Notify %company% + +you can specify placeholder value: + +.. code-block:: php + + use Symfony\Component\Form\Extension\Core\Type\ChoiceType; + // ... + + $builder->add('send', ChoiceType::class, array( + // ... + 'label' => 'form.order_list.notify', + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +Note that `translation_parameters` of choice fields are merged with those of parent. +In other words the parent's parameters are available for choice fields +but can be overriden: + +.. code-block:: php + + // App\Controller\OrderListController + + $form = $this->createForm(OrderListType::class, null, array( + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +.. code-block:: php + + // App\Form\OrderListType + use Symfony\Component\Form\Extension\Core\Type\ChoiceType; + // ... + + $builder->add('send', ChoiceType::class, array( + // ... + 'label' => 'form.order_list.notify', + )); diff --git a/reference/forms/types/options/entity_type_translation_parameters.rst.inc b/reference/forms/types/options/entity_type_translation_parameters.rst.inc new file mode 100644 index 00000000000..500a26dbce8 --- /dev/null +++ b/reference/forms/types/options/entity_type_translation_parameters.rst.inc @@ -0,0 +1,56 @@ +translation_parameters +~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_, `help`_ and some attr_ (``title``, ``placeholder``) can +contain :ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order_list.notify: Notify %company% + +you can specify placeholder value: + +.. code-block:: php + + use Symfony\Component\Form\Extension\Core\Type\EntityType; + // ... + + $builder->add('send', EntityType::class, array( + // ... + 'label' => 'form.order_list.notify', + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +Note that `translation_parameters` of entity fields are merged with those of parent. +In other words the parent's parameters are available for entity fields +but can be overriden: + +.. code-block:: php + + // App\Controller\OrderListController + + $form = $this->createForm(OrderListType::class, null, array( + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +.. code-block:: php + + // App\Form\OrderListType + use Symfony\Component\Form\Extension\Core\Type\EntityType; + // ... + + $builder->add('send', EntityType::class, array( + // ... + 'label' => 'form.order_list.notify', + )); diff --git a/reference/forms/types/options/reset_translation_parameters.rst.inc b/reference/forms/types/options/reset_translation_parameters.rst.inc new file mode 100644 index 00000000000..8aa588073ef --- /dev/null +++ b/reference/forms/types/options/reset_translation_parameters.rst.inc @@ -0,0 +1,54 @@ +translation_parameters +~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_ can contain +:ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order_list.submit_to_company: Send an order to %company% + +you can specify placeholder value: + +.. code-block:: php + + use Symfony\Component\Form\Extension\Core\Type\ResetType; + // ... + + $builder->add('send', ResetType::class, array( + 'label' => 'form.order_list.submit_to_company', + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +Note that `translation_parameters` of reset fields are merged with those of +parent form. In other words the parent's parameters are available for reset +fields but can be overriden: + +.. code-block:: php + + // App\Controller\OrderListController + + $form = $this->createForm(OrderListType::class, null, array( + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +.. code-block:: php + + // App\Form\OrderListType + use Symfony\Component\Form\Extension\Core\Type\ResetType; + // ... + + $builder->add('send', ResetType::class, array( + 'label' => 'form.order_list.submit_to_company', + )); diff --git a/reference/forms/types/options/submit_translation_parameters.rst.inc b/reference/forms/types/options/submit_translation_parameters.rst.inc new file mode 100644 index 00000000000..b6affc8253b --- /dev/null +++ b/reference/forms/types/options/submit_translation_parameters.rst.inc @@ -0,0 +1,54 @@ +translation_parameters +~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_ can contain +:ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order_list.submit_to_company: Send an order to %company% + +you can specify placeholder value: + +.. code-block:: php + + use Symfony\Component\Form\Extension\Core\Type\SubmitType; + // ... + + $builder->add('send', SubmitType::class, array( + 'label' => 'form.order_list.submit_to_company', + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +Note that `translation_parameters` of submit fields are merged with those of +parent. In other words the parent's parameters are available for submit fields +but can be overriden: + +.. code-block:: php + + // App\Controller\OrderListController + + $form = $this->createForm(OrderListType::class, null, array( + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +.. code-block:: php + + // App\Form\OrderListType + use Symfony\Component\Form\Extension\Core\Type\SubmitType; + // ... + + $builder->add('send', SubmitType::class, array( + 'label' => 'form.order_list.submit_to_company', + )); diff --git a/reference/forms/types/options/translation_parameters.rst.inc b/reference/forms/types/options/translation_parameters.rst.inc new file mode 100644 index 00000000000..86689515fe7 --- /dev/null +++ b/reference/forms/types/options/translation_parameters.rst.inc @@ -0,0 +1,49 @@ +translation_parameters +~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_, `help`_ and some attr_ (``title``, ``placeholder``) can +contain :ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order_list.id: Identifier of the order to %company% + +you can specify placeholder value: + +.. code-block:: php + + $builder->add('id', null, array( + 'label' => 'form.order_list.id', + 'translation_parameters' => [ + '%company%' => 'ACME Inc.' + ] + )); + +Note that `translation_parameters` of children fields are merged with those +of parent. In other words the parent's parameters are available for children +but can be overriden: + +.. code-block:: php + + // App\Controller\OrderListController + + $form = $this->createForm(OrderListType::class, null, array( + 'translation_parameters' => array( + '%company%' => 'ACME Inc.' + ) + )); + +.. code-block:: php + + // App\Form\OrderListType + + $builder->add('id', null, array( + 'label' => 'form.order_list.id' + )); diff --git a/reference/forms/types/reset.rst b/reference/forms/types/reset.rst index f9363b0257b..a73410a314c 100644 --- a/reference/forms/types/reset.rst +++ b/reference/forms/types/reset.rst @@ -13,6 +13,7 @@ A button that resets all fields to their original values. | options | - `disabled`_ | | | - `label`_ | | | - `translation_domain`_ | +| | - `translation_parameters`_ | +----------------------+---------------------------------------------------------------------+ | Parent type | :doc:`ButtonType ` | +----------------------+---------------------------------------------------------------------+ @@ -45,3 +46,5 @@ as a key. This can be useful when you need to set a custom class for the button: .. include:: /reference/forms/types/options/button_label.rst.inc .. include:: /reference/forms/types/options/button_translation_domain.rst.inc + +.. include:: /reference/forms/types/options/reset_translation_parameters.rst.inc diff --git a/reference/forms/types/submit.rst b/reference/forms/types/submit.rst index bdb7a92d12a..8a408f335f5 100644 --- a/reference/forms/types/submit.rst +++ b/reference/forms/types/submit.rst @@ -14,6 +14,7 @@ A submit button. | | - `label`_ | | | - `label_format`_ | | | - `translation_domain`_ | +| | - `translation_parameters`_ | | | - `validation_groups`_ | +----------------------+----------------------------------------------------------------------+ | Parent type | :doc:`ButtonType` | @@ -59,6 +60,8 @@ as a key. This can be useful when you need to set a custom class for the button: .. include:: /reference/forms/types/options/button_translation_domain.rst.inc +.. include:: /reference/forms/types/options/submit_translation_parameters.rst.inc + validation_groups ~~~~~~~~~~~~~~~~~ diff --git a/templating/PHP.rst b/templating/PHP.rst index 6e89a46964b..743082806f7 100644 --- a/templating/PHP.rst +++ b/templating/PHP.rst @@ -532,7 +532,7 @@ original template: humanize($name); } ?> - + From 32e79e10ada23b84f3dd4daa0f2cc92f85b7c17f Mon Sep 17 00:00:00 2001 From: Webnet team Date: Fri, 13 Jul 2018 16:00:09 +0200 Subject: [PATCH 009/499] correct link error --- .../types/options/entity_type_translation_parameters.rst.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/options/entity_type_translation_parameters.rst.inc b/reference/forms/types/options/entity_type_translation_parameters.rst.inc index 500a26dbce8..71cd2cfcfba 100644 --- a/reference/forms/types/options/entity_type_translation_parameters.rst.inc +++ b/reference/forms/types/options/entity_type_translation_parameters.rst.inc @@ -3,7 +3,7 @@ translation_parameters **type**: ``array`` **default**: ``array()`` -Translated `label`_, `help`_ and some attr_ (``title``, ``placeholder``) can +Translated `label`_, `help`_ and some ``attr`` (``title``, ``placeholder``) can contain :ref:`placeholders `. This option allows you to pass an array of parameters in order to replace placeholders with actual values. From a6551061f053d6c61a61c7ffc67e9b9a691bbd1f Mon Sep 17 00:00:00 2001 From: Vladyslav Riabchenko Date: Tue, 12 Feb 2019 14:10:07 +0100 Subject: [PATCH 010/499] confirm with 28635 --- reference/forms/types/button.rst | 83 ++++++++++++++++++- reference/forms/types/choice.rst | 10 ++- reference/forms/types/entity.rst | 10 ++- reference/forms/types/form.rst | 9 +- .../attr_translation_parameters.rst.inc | 82 ++++++++++++++++++ .../button_translation_parameters.rst.inc | 54 ------------ ...choice_type_translation_parameters.rst.inc | 56 ------------- ...entity_type_translation_parameters.rst.inc | 56 ------------- .../help_translation_parameters.rst.inc | 72 ++++++++++++++++ .../label_translation_parameters.rst.inc | 72 ++++++++++++++++ .../reset_translation_parameters.rst.inc | 54 ------------ .../submit_translation_parameters.rst.inc | 54 ------------ .../options/translation_parameters.rst.inc | 49 ----------- reference/forms/types/reset.rst | 83 ++++++++++++++++++- reference/forms/types/submit.rst | 83 ++++++++++++++++++- 15 files changed, 493 insertions(+), 334 deletions(-) create mode 100644 reference/forms/types/options/attr_translation_parameters.rst.inc delete mode 100644 reference/forms/types/options/button_translation_parameters.rst.inc delete mode 100644 reference/forms/types/options/choice_type_translation_parameters.rst.inc delete mode 100644 reference/forms/types/options/entity_type_translation_parameters.rst.inc create mode 100644 reference/forms/types/options/help_translation_parameters.rst.inc create mode 100644 reference/forms/types/options/label_translation_parameters.rst.inc delete mode 100644 reference/forms/types/options/reset_translation_parameters.rst.inc delete mode 100644 reference/forms/types/options/submit_translation_parameters.rst.inc delete mode 100644 reference/forms/types/options/translation_parameters.rst.inc diff --git a/reference/forms/types/button.rst b/reference/forms/types/button.rst index 4d84f397267..4f17fbf03ac 100644 --- a/reference/forms/types/button.rst +++ b/reference/forms/types/button.rst @@ -13,7 +13,8 @@ A simple, non-responsive button. | options | - `disabled`_ | | | - `label`_ | | | - `translation_domain`_ | -| | - `translation_parameters`_ | +| | - `label_translation_parameters`_ | +| | - `attr_translation_parameters`_ | +----------------------+----------------------------------------------------------------------+ | Parent type | none | +----------------------+----------------------------------------------------------------------+ @@ -53,4 +54,82 @@ as a key. This can be useful when you need to set a custom class for the button: .. include:: /reference/forms/types/options/button_translation_domain.rst.inc -.. include:: /reference/forms/types/options/button_translation_parameters.rst.inc +label_translation_parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_ can contain +:ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order.submit_to_company: Send an order to %company% + +you can specify placeholder value: + +.. code-block:: php + + use Symfony\Component\Form\Extension\Core\Type\ButtonType; + // ... + + $builder->add('send', ButtonType::class, array( + 'label' => 'form.order.submit_to_company', + 'label_translation_parameters' => array( + '%company%' => 'ACME Inc.', + ), + )); + +Note that `label_translation_parameters` of buttons are merged with those of its +parent. In other words the parent's translation parameters are available for +children's buttons but can be overriden: + +.. code-block:: php + + // App/Controller/OrderController.php + use App\Form\OrderType; + // ... + + $form = $this->createForm(OrderType::class, $order, array( + // available to all children, grandchildren and so on. + 'label_translation_parameters' => array( + '%company%' => 'ACME', + ), + )); + +.. code-block:: php + + // App/Form/OrderType.php + use Symfony\Component\Form\Extension\Core\Type\ButtonType; + // ... + + $builder->add('send', ButtonType::class, array( + 'label' => 'form.order.submit_to_company', + // Value of parent's 'label_translation_parameters' will be merged with + // this field's empty 'label_translation_parameters'. + // array('%company%' => 'ACME') will be used to translate this label. + )); + +.. code-block:: php + + // App/Form/OrderType.php + use Symfony\Component\Form\Extension\Core\Type\ButtonType; + // ... + + $builder->add('send', ButtonType::class, array( + 'label' => 'form.order.submit_to_company', + 'label_translation_parameters' => array( + '%company%' => 'American Company Making Everything', + ), + // Value of parent's 'label_translation_parameters' will be merged with + // this button's 'label_translation_parameters'. + // array('%company%' => 'American Company Making Everything') + // will be used to translate this label. + )); + +.. include:: /reference/forms/types/options/attr_translation_parameters.rst.inc diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index ad47316b948..aea19be951d 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -45,7 +45,9 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | | - `mapped`_ | | | - `required`_ | | | - `translation_domain`_ | -| | - `translation_parameters`_ | +| | - `label_translation_parameters`_ | +| | - `attr_translation_parameters`_ | +| | - `helptranslation_parameters`_ | +-------------+------------------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +-------------+------------------------------------------------------------------------------+ @@ -298,7 +300,11 @@ These options inherit from the :doc:`FormType `: .. include:: /reference/forms/types/options/choice_type_translation_domain.rst.inc -.. include:: /reference/forms/types/options/choice_type_translation_parameters.rst.inc +.. 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/help_translation_parameters.rst.inc Field Variables --------------- diff --git a/reference/forms/types/entity.rst b/reference/forms/types/entity.rst index db645c3f9a8..cad2f8c64b6 100644 --- a/reference/forms/types/entity.rst +++ b/reference/forms/types/entity.rst @@ -32,7 +32,9 @@ objects from the database. | | - `placeholder`_ | | | - `preferred_choices`_ | | | - `translation_domain`_ | -| | - `translation_parameters`_ | +| | - `label_translation_parameters`_ | +| | - `attr_translation_parameters`_ | +| | - `help_translation_parameters`_ | | | - `trim`_ | | | | | | from the :doc:`FormType `: | @@ -308,7 +310,11 @@ when rendering the field: .. include:: /reference/forms/types/options/choice_type_translation_domain.rst.inc -.. include:: /reference/forms/types/options/entity_type_translation_parameters.rst.inc +.. 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/help_translation_parameters.rst.inc .. include:: /reference/forms/types/options/choice_type_trim.rst.inc diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index 45e4d3c841b..d8fe5f4c9c1 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -22,6 +22,7 @@ on all types for which ``FormType`` is the parent. | | - `help`_ | | | - `help_attr`_ | | | - `help_html`_ | +| | - `help_translation_parameters`_ | | | - `inherit_data`_ | | | - `invalid_message`_ | | | - `invalid_message_parameters`_ | @@ -42,6 +43,8 @@ on all types for which ``FormType`` is the parent. | | - `disabled`_ | | | - `label`_ | | | - `translation_domain`_ | +| | - `label_translation_parameters`_ | +| | - `attr_translation_parameters`_ | | | - `translation_parameters`_ | +-----------+--------------------------------------------------------------------+ | Parent | none | @@ -114,6 +117,8 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/help_html.rst.inc +.. include:: /reference/forms/types/options/help_translation_parameters.rst.inc + .. include:: /reference/forms/types/options/inherit_data.rst.inc .. include:: /reference/forms/types/options/invalid_message.rst.inc @@ -169,4 +174,6 @@ of the form type tree (i.e. it cannot be used as a form type on its own). .. include:: /reference/forms/types/options/translation_domain.rst.inc -.. include:: /reference/forms/types/options/translation_parameters.rst.inc +.. include:: /reference/forms/types/options/label_translation_parameters.rst.inc + +.. include:: /reference/forms/types/options/attr_translation_parameters.rst.inc diff --git a/reference/forms/types/options/attr_translation_parameters.rst.inc b/reference/forms/types/options/attr_translation_parameters.rst.inc new file mode 100644 index 00000000000..362fd5f4820 --- /dev/null +++ b/reference/forms/types/options/attr_translation_parameters.rst.inc @@ -0,0 +1,82 @@ +attr_translation_parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Some translated `attr`_ (``title`` and ``placeholder``) can +contain :ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order.id.placeholder: Enter unique identifier of the order to %company% + form.order.id.title: This will be the reference in communications with %company% + +you can specify placeholder value: + +.. code-block:: php + + $builder->add('id', null, array( + 'attr' => array( + 'placeholder' => 'form.order.id.placeholder', + 'title' => 'form.order.id.title', + ), + 'attr_translation_parameters' => [ + '%company%' => 'ACME Inc.' + ] + )); + +Note that `attr_translation_parameters` of children fields are merged with those +of its parent. In other words the parent's translation parameters are available +for children but can be overriden: + +.. code-block:: php + + // App/Controller/OrderController.php + use App\Form\OrderType; + // ... + + $form = $this->createForm(OrderType::class, $order, array( + // available to all children, grandchildren and so on. + 'attr_translation_parameters' => array( + '%company%' => 'ACME', + ), + )); + + .. code-block:: php + + // App/Form/OrderType.php + // ... + + $builder->add('id', null, array( + 'attr' => array( + 'placeholder' => 'form.order.id.placeholder', + 'title' => 'form.order.id.title', + ), + // Value of parent's 'attr_translation_parameters' will be merged with + // this field's empty 'attr_translation_parameters'. + // array('%company%' => 'ACME') will be used to translate 'placeholder' and 'title'. + )); + + .. code-block:: php + + // App/Form/OrderType.php + // ... + + $builder->add('id', null, array( + 'attr' => array( + 'placeholder' => 'form.order.id.placeholder', + 'title' => 'form.order.id.title', + ), + 'attr_translation_parameters' => array( + '%company%' => 'American Company Making Everything', + ), + // Value of parent's 'attr_translation_parameters' will be merged with + // this field's 'attr_translation_parameters'. + // array('%company%' => 'American Company Making Everything') + // will be used to translate 'placeholder' and 'title'. + )); diff --git a/reference/forms/types/options/button_translation_parameters.rst.inc b/reference/forms/types/options/button_translation_parameters.rst.inc deleted file mode 100644 index 81c2a44838e..00000000000 --- a/reference/forms/types/options/button_translation_parameters.rst.inc +++ /dev/null @@ -1,54 +0,0 @@ -translation_parameters -~~~~~~~~~~~~~~~~~~~~~~ - -**type**: ``array`` **default**: ``array()`` - -Translated `label`_ can contain -:ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. - -Given this translation message: - -.. code-block:: yaml - - # translations/messages.en.yml - form.order_list.submit_to_company: Send an order to %company% - -you can specify placeholder value: - -.. code-block:: php - - use Symfony\Component\Form\Extension\Core\Type\ButtonType; - // ... - - $builder->add('send', ButtonType::class, array( - 'label' => 'form.order_list.submit_to_company', - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -Note that `translation_parameters` of buttons are merged with those of parent. -In other words the parent's parameters are available for buttons but can be -overriden: - -.. code-block:: php - - // App\Controller\OrderListController - - $form = $this->createForm(OrderListType::class, null, array( - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -.. code-block:: php - - // App\Form\OrderListType - use Symfony\Component\Form\Extension\Core\Type\ButtonType; - // ... - - $builder->add('send', ButtonType::class, array( - 'label' => 'form.order_list.submit_to_company', - )); diff --git a/reference/forms/types/options/choice_type_translation_parameters.rst.inc b/reference/forms/types/options/choice_type_translation_parameters.rst.inc deleted file mode 100644 index 6425dbca3c8..00000000000 --- a/reference/forms/types/options/choice_type_translation_parameters.rst.inc +++ /dev/null @@ -1,56 +0,0 @@ -translation_parameters -~~~~~~~~~~~~~~~~~~~~~~ - -**type**: ``array`` **default**: ``array()`` - -Translated `label`_, `help`_ and some attr_ (``title``, ``placeholder``) can -contain :ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. - -Given this translation message: - -.. code-block:: yaml - - # translations/messages.en.yml - form.order_list.notify: Notify %company% - -you can specify placeholder value: - -.. code-block:: php - - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('send', ChoiceType::class, array( - // ... - 'label' => 'form.order_list.notify', - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -Note that `translation_parameters` of choice fields are merged with those of parent. -In other words the parent's parameters are available for choice fields -but can be overriden: - -.. code-block:: php - - // App\Controller\OrderListController - - $form = $this->createForm(OrderListType::class, null, array( - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -.. code-block:: php - - // App\Form\OrderListType - use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - // ... - - $builder->add('send', ChoiceType::class, array( - // ... - 'label' => 'form.order_list.notify', - )); diff --git a/reference/forms/types/options/entity_type_translation_parameters.rst.inc b/reference/forms/types/options/entity_type_translation_parameters.rst.inc deleted file mode 100644 index 71cd2cfcfba..00000000000 --- a/reference/forms/types/options/entity_type_translation_parameters.rst.inc +++ /dev/null @@ -1,56 +0,0 @@ -translation_parameters -~~~~~~~~~~~~~~~~~~~~~~ - -**type**: ``array`` **default**: ``array()`` - -Translated `label`_, `help`_ and some ``attr`` (``title``, ``placeholder``) can -contain :ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. - -Given this translation message: - -.. code-block:: yaml - - # translations/messages.en.yml - form.order_list.notify: Notify %company% - -you can specify placeholder value: - -.. code-block:: php - - use Symfony\Component\Form\Extension\Core\Type\EntityType; - // ... - - $builder->add('send', EntityType::class, array( - // ... - 'label' => 'form.order_list.notify', - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -Note that `translation_parameters` of entity fields are merged with those of parent. -In other words the parent's parameters are available for entity fields -but can be overriden: - -.. code-block:: php - - // App\Controller\OrderListController - - $form = $this->createForm(OrderListType::class, null, array( - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -.. code-block:: php - - // App\Form\OrderListType - use Symfony\Component\Form\Extension\Core\Type\EntityType; - // ... - - $builder->add('send', EntityType::class, array( - // ... - 'label' => 'form.order_list.notify', - )); diff --git a/reference/forms/types/options/help_translation_parameters.rst.inc b/reference/forms/types/options/help_translation_parameters.rst.inc new file mode 100644 index 00000000000..cd0755c0cde --- /dev/null +++ b/reference/forms/types/options/help_translation_parameters.rst.inc @@ -0,0 +1,72 @@ +help_translation_parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `help`_ can +contain :ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order.id.help: This will be the reference in communications with %company% + +you can specify placeholder value: + +.. code-block:: php + + $builder->add('id', null, array( + 'help' => 'form.order.id.help', + 'help_translation_parameters' => [ + '%company%' => 'ACME Inc.' + ] + )); + +Note that `help_translation_parameters` of children fields are merged with those +of its parent. In other words the parent's translation parameters are available +for children but can be overriden: + +.. code-block:: php + + // App/Controller/OrderController.php + use App\Form\OrderType; + // ... + + $form = $this->createForm(OrderType::class, $order, array( + // available to all children, grandchildren and so on. + 'help_translation_parameters' => array( + '%company%' => 'ACME', + ), + )); + + .. code-block:: php + + // App/Form/OrderType.php + // ... + + $builder->add('id', null, array( + 'help' => 'form.order.id.help', + // Value of parent's 'help_translation_parameters' will be merged with + // this field's empty 'help_translation_parameters'. + // array('%company%' => 'ACME') will be used to translate 'help'. + )); + + .. code-block:: php + + // App/Form/OrderType.php + // ... + + $builder->add('id', null, array( + 'help' => 'form.order.id.help', + 'help_translation_parameters' => array( + '%company%' => 'American Company Making Everything', + ), + // Value of parent's 'help_translation_parameters' will be merged with + // this field's 'help_translation_parameters'. + // array('%company%' => 'American Company Making Everything') + // will be used to translate 'help'. + )); diff --git a/reference/forms/types/options/label_translation_parameters.rst.inc b/reference/forms/types/options/label_translation_parameters.rst.inc new file mode 100644 index 00000000000..aec761841ce --- /dev/null +++ b/reference/forms/types/options/label_translation_parameters.rst.inc @@ -0,0 +1,72 @@ +label_translation_parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_, can +contain :ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order.id: Identifier of the order to %company% + +you can specify placeholder value: + +.. code-block:: php + + $builder->add('id', null, array( + 'label' => 'form.order.id', + 'label_translation_parameters' => [ + '%company%' => 'ACME Inc.' + ] + )); + +Note that `label_translation_parameters` of children fields are merged with those +of its parent. In other words the parent's translation parameters are available +for children but can be overriden: + +.. code-block:: php + + // App/Controller/OrderController.php + use App\Form\OrderType; + // ... + + $form = $this->createForm(OrderType::class, $order, array( + // available to all children, grandchildren and so on. + 'label_translation_parameters' => array( + '%company%' => 'ACME', + ), + )); + + .. code-block:: php + + // App/Form/OrderType.php + // ... + + $builder->add('id', null, array( + 'label' => 'form.order.id', + // Value of parent's 'label_translation_parameters' will be merged with + // this field's empty 'label_translation_parameters'. + // array('%company%' => 'ACME') will be used to translate this label. + )); + + .. code-block:: php + + // App/Form/OrderType.php + // ... + + $builder->add('id', null, array( + 'label' => 'form.order.id', + 'label_translation_parameters' => array( + '%company%' => 'American Company Making Everything', + ), + // Value of parent's 'label_translation_parameters' will be merged with + // this field's 'label_translation_parameters'. + // array('%company%' => 'American Company Making Everything') + // will be used to translate this label. + )); diff --git a/reference/forms/types/options/reset_translation_parameters.rst.inc b/reference/forms/types/options/reset_translation_parameters.rst.inc deleted file mode 100644 index 8aa588073ef..00000000000 --- a/reference/forms/types/options/reset_translation_parameters.rst.inc +++ /dev/null @@ -1,54 +0,0 @@ -translation_parameters -~~~~~~~~~~~~~~~~~~~~~~ - -**type**: ``array`` **default**: ``array()`` - -Translated `label`_ can contain -:ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. - -Given this translation message: - -.. code-block:: yaml - - # translations/messages.en.yml - form.order_list.submit_to_company: Send an order to %company% - -you can specify placeholder value: - -.. code-block:: php - - use Symfony\Component\Form\Extension\Core\Type\ResetType; - // ... - - $builder->add('send', ResetType::class, array( - 'label' => 'form.order_list.submit_to_company', - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -Note that `translation_parameters` of reset fields are merged with those of -parent form. In other words the parent's parameters are available for reset -fields but can be overriden: - -.. code-block:: php - - // App\Controller\OrderListController - - $form = $this->createForm(OrderListType::class, null, array( - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -.. code-block:: php - - // App\Form\OrderListType - use Symfony\Component\Form\Extension\Core\Type\ResetType; - // ... - - $builder->add('send', ResetType::class, array( - 'label' => 'form.order_list.submit_to_company', - )); diff --git a/reference/forms/types/options/submit_translation_parameters.rst.inc b/reference/forms/types/options/submit_translation_parameters.rst.inc deleted file mode 100644 index b6affc8253b..00000000000 --- a/reference/forms/types/options/submit_translation_parameters.rst.inc +++ /dev/null @@ -1,54 +0,0 @@ -translation_parameters -~~~~~~~~~~~~~~~~~~~~~~ - -**type**: ``array`` **default**: ``array()`` - -Translated `label`_ can contain -:ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. - -Given this translation message: - -.. code-block:: yaml - - # translations/messages.en.yml - form.order_list.submit_to_company: Send an order to %company% - -you can specify placeholder value: - -.. code-block:: php - - use Symfony\Component\Form\Extension\Core\Type\SubmitType; - // ... - - $builder->add('send', SubmitType::class, array( - 'label' => 'form.order_list.submit_to_company', - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -Note that `translation_parameters` of submit fields are merged with those of -parent. In other words the parent's parameters are available for submit fields -but can be overriden: - -.. code-block:: php - - // App\Controller\OrderListController - - $form = $this->createForm(OrderListType::class, null, array( - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -.. code-block:: php - - // App\Form\OrderListType - use Symfony\Component\Form\Extension\Core\Type\SubmitType; - // ... - - $builder->add('send', SubmitType::class, array( - 'label' => 'form.order_list.submit_to_company', - )); diff --git a/reference/forms/types/options/translation_parameters.rst.inc b/reference/forms/types/options/translation_parameters.rst.inc deleted file mode 100644 index 86689515fe7..00000000000 --- a/reference/forms/types/options/translation_parameters.rst.inc +++ /dev/null @@ -1,49 +0,0 @@ -translation_parameters -~~~~~~~~~~~~~~~~~~~~~~ - -**type**: ``array`` **default**: ``array()`` - -Translated `label`_, `help`_ and some attr_ (``title``, ``placeholder``) can -contain :ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. - -Given this translation message: - -.. code-block:: yaml - - # translations/messages.en.yml - form.order_list.id: Identifier of the order to %company% - -you can specify placeholder value: - -.. code-block:: php - - $builder->add('id', null, array( - 'label' => 'form.order_list.id', - 'translation_parameters' => [ - '%company%' => 'ACME Inc.' - ] - )); - -Note that `translation_parameters` of children fields are merged with those -of parent. In other words the parent's parameters are available for children -but can be overriden: - -.. code-block:: php - - // App\Controller\OrderListController - - $form = $this->createForm(OrderListType::class, null, array( - 'translation_parameters' => array( - '%company%' => 'ACME Inc.' - ) - )); - -.. code-block:: php - - // App\Form\OrderListType - - $builder->add('id', null, array( - 'label' => 'form.order_list.id' - )); diff --git a/reference/forms/types/reset.rst b/reference/forms/types/reset.rst index a73410a314c..394e113cd82 100644 --- a/reference/forms/types/reset.rst +++ b/reference/forms/types/reset.rst @@ -13,7 +13,8 @@ A button that resets all fields to their original values. | options | - `disabled`_ | | | - `label`_ | | | - `translation_domain`_ | -| | - `translation_parameters`_ | +| | - `label_translation_parameters`_ | +| | - `attr_translation_parameters`_ | +----------------------+---------------------------------------------------------------------+ | Parent type | :doc:`ButtonType ` | +----------------------+---------------------------------------------------------------------+ @@ -47,4 +48,82 @@ as a key. This can be useful when you need to set a custom class for the button: .. include:: /reference/forms/types/options/button_translation_domain.rst.inc -.. include:: /reference/forms/types/options/reset_translation_parameters.rst.inc +label_translation_parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_ can contain +:ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order.reset: Reset an order to %company% + +you can specify placeholder value: + +.. code-block:: php + + use Symfony\Component\Form\Extension\Core\Type\ResetType; + // ... + + $builder->add('send', ResetType::class, array( + 'label' => 'form.order.reset', + 'label_translation_parameters' => array( + '%company%' => 'ACME Inc.', + ), + )); + +Note that `label_translation_parameters` of resets are merged with those of its +parent. In other words the parent's translation parameters are available for +children's resets but can be overriden: + +.. code-block:: php + + // App/Controller/OrderController.php + use App\Form\OrderType; + // ... + + $form = $this->createForm(OrderType::class, $order, array( + // available to all children, grandchildren and so on. + 'label_translation_parameters' => array( + '%company%' => 'ACME', + ), + )); + +.. code-block:: php + + // App/Form/OrderType.php + use Symfony\Component\Form\Extension\Core\Type\ResetType; + // ... + + $builder->add('send', ResetType::class, array( + 'label' => 'form.order.reset', + // Value of parent's 'label_translation_parameters' will be merged with + // this field's empty 'label_translation_parameters'. + // array('%company%' => 'ACME') will be used to translate this label. + )); + +.. code-block:: php + + // App/Form/OrderType.php + use Symfony\Component\Form\Extension\Core\Type\ResetType; + // ... + + $builder->add('send', ResetType::class, array( + 'label' => 'form.order.reset', + 'label_translation_parameters' => array( + '%company%' => 'American Company Making Everything', + ), + // Value of parent's 'label_translation_parameters' will be merged with + // this reset's 'label_translation_parameters'. + // array('%company%' => 'American Company Making Everything') + // will be passed to translate this label. + )); + +.. include:: /reference/forms/types/options/attr_translation_parameters.rst.inc diff --git a/reference/forms/types/submit.rst b/reference/forms/types/submit.rst index 8a408f335f5..3c2b741280e 100644 --- a/reference/forms/types/submit.rst +++ b/reference/forms/types/submit.rst @@ -14,7 +14,8 @@ A submit button. | | - `label`_ | | | - `label_format`_ | | | - `translation_domain`_ | -| | - `translation_parameters`_ | +| | - `label_translation_parameters`_ | +| | - `attr_translation_parameters`_ | | | - `validation_groups`_ | +----------------------+----------------------------------------------------------------------+ | Parent type | :doc:`ButtonType` | @@ -60,7 +61,85 @@ as a key. This can be useful when you need to set a custom class for the button: .. include:: /reference/forms/types/options/button_translation_domain.rst.inc -.. include:: /reference/forms/types/options/submit_translation_parameters.rst.inc +label_translation_parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` **default**: ``array()`` + +Translated `label`_ can contain +:ref:`placeholders `. +This option allows you to pass an array of parameters in order to replace +placeholders with actual values. + +Given this translation message: + +.. code-block:: yaml + + # translations/messages.en.yml + form.order.submit_to_company: Send an order to %company% + +you can specify placeholder value: + +.. code-block:: php + + use Symfony\Component\Form\Extension\Core\Type\SubmitType; + // ... + + $builder->add('send', SubmitType::class, array( + 'label' => 'form.order.submit_to_company', + 'label_translation_parameters' => array( + '%company%' => 'ACME Inc.', + ), + )); + +Note that `label_translation_parameters` of submits are merged with those of its +parent. In other words the parent's translation parameters are available for +children's submits but can be overriden: + +.. code-block:: php + + // App/Controller/OrderController.php + use App\Form\OrderType; + // ... + + $form = $this->createForm(OrderType::class, $order, array( + // available to all children, grandchildren and so on. + 'label_translation_parameters' => array( + '%company%' => 'ACME', + ), + )); + +.. code-block:: php + + // App/Form/OrderType.php + use Symfony\Component\Form\Extension\Core\Type\SubmitType; + // ... + + $builder->add('send', SubmitType::class, array( + 'label' => 'form.order.submit_to_company', + // Value of parent's 'label_translation_parameters' will be merged with + // this field's empty 'label_translation_parameters'. + // array('%company%' => 'ACME') will be used to translate this label. + )); + +.. code-block:: php + + // App/Form/OrderType.php + use Symfony\Component\Form\Extension\Core\Type\SubmitType; + // ... + + $builder->add('send', SubmitType::class, array( + 'label' => 'form.order.submit_to_company', + 'label_translation_parameters' => array( + '%company%' => 'American Company Making Everything', + ), + // Value of parent's 'label_translation_parameters' will be merged with + // this submit's 'label_translation_parameters'. + // array('%company%' => 'American Company Making Everything') + // will be passed to translate this label. + )); + +.. include:: /reference/forms/types/options/attr_translation_parameters.rst.inc validation_groups ~~~~~~~~~~~~~~~~~ From 71fc7ce1eaeff78f3897a3a76e832a12304858b8 Mon Sep 17 00:00:00 2001 From: Vladyslav Riabchenko Date: Tue, 12 Feb 2019 14:23:50 +0100 Subject: [PATCH 011/499] typo in form_translation_parameters docs --- reference/forms/types/choice.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index aea19be951d..8ef9984c8ca 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -47,7 +47,7 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | | - `translation_domain`_ | | | - `label_translation_parameters`_ | | | - `attr_translation_parameters`_ | -| | - `helptranslation_parameters`_ | +| | - `help_translation_parameters`_ | +-------------+------------------------------------------------------------------------------+ | Parent type | :doc:`FormType ` | +-------------+------------------------------------------------------------------------------+ From d7e7b0b22cc7f5cc24d5d5ccadef32d79aa5ca32 Mon Sep 17 00:00:00 2001 From: Vladyslav Riabchenko Date: Tue, 12 Feb 2019 16:19:01 +0100 Subject: [PATCH 012/499] correct attr link in entity type doc --- reference/forms/types/entity.rst | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/reference/forms/types/entity.rst b/reference/forms/types/entity.rst index cad2f8c64b6..af1e934dd61 100644 --- a/reference/forms/types/entity.rst +++ b/reference/forms/types/entity.rst @@ -32,13 +32,11 @@ objects from the database. | | - `placeholder`_ | | | - `preferred_choices`_ | | | - `translation_domain`_ | -| | - `label_translation_parameters`_ | -| | - `attr_translation_parameters`_ | -| | - `help_translation_parameters`_ | | | - `trim`_ | | | | | | from the :doc:`FormType `: | | | | +| | - `attr`_ | | | - `data`_ | | | - `disabled`_ | | | - `empty_data`_ | @@ -52,6 +50,9 @@ objects from the database. | | - `label_format`_ | | | - `mapped`_ | | | - `required`_ | +| | - `label_translation_parameters`_ | +| | - `attr_translation_parameters`_ | +| | - `help_translation_parameters`_ | +-------------+------------------------------------------------------------------+ | Parent type | :doc:`ChoiceType ` | +-------------+------------------------------------------------------------------+ @@ -310,17 +311,13 @@ when rendering the field: .. include:: /reference/forms/types/options/choice_type_translation_domain.rst.inc -.. 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/help_translation_parameters.rst.inc - .. include:: /reference/forms/types/options/choice_type_trim.rst.inc These options inherit from the :doc:`form ` type: +.. include:: /reference/forms/types/options/attr.rst.inc + .. include:: /reference/forms/types/options/data.rst.inc .. include:: /reference/forms/types/options/disabled.rst.inc @@ -356,3 +353,9 @@ The actual default value of this option depends on other field options: .. include:: /reference/forms/types/options/mapped.rst.inc .. include:: /reference/forms/types/options/required.rst.inc + +.. 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/help_translation_parameters.rst.inc From 70f36aded8fdbfa3ff204a53733d586f9efce5b0 Mon Sep 17 00:00:00 2001 From: Vladyslav Riabchenko Date: Tue, 12 Feb 2019 16:57:23 +0100 Subject: [PATCH 013/499] correct bug --- reference/forms/types/form.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index d8fe5f4c9c1..9d38ab840cc 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -45,7 +45,6 @@ on all types for which ``FormType`` is the parent. | | - `translation_domain`_ | | | - `label_translation_parameters`_ | | | - `attr_translation_parameters`_ | -| | - `translation_parameters`_ | +-----------+--------------------------------------------------------------------+ | Parent | none | +-----------+--------------------------------------------------------------------+ From 20c6f5a991b806a03099033c6ae21c8e6b4c52c8 Mon Sep 17 00:00:00 2001 From: Vladyslav Riabchenko Date: Wed, 13 Feb 2019 10:46:09 +0100 Subject: [PATCH 014/499] correct arrays short syntax --- reference/forms/types/button.rst | 4 ++-- .../forms/types/options/attr_translation_parameters.rst.inc | 4 ++-- .../forms/types/options/help_translation_parameters.rst.inc | 4 ++-- .../forms/types/options/label_translation_parameters.rst.inc | 4 ++-- reference/forms/types/reset.rst | 4 ++-- reference/forms/types/submit.rst | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/reference/forms/types/button.rst b/reference/forms/types/button.rst index 4f17fbf03ac..4d0459b489c 100644 --- a/reference/forms/types/button.rst +++ b/reference/forms/types/button.rst @@ -57,7 +57,7 @@ as a key. This can be useful when you need to set a custom class for the button: label_translation_parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``array`` **default**: ``array()`` +**type**: ``array`` **default**: ``[]`` Translated `label`_ can contain :ref:`placeholders `. @@ -85,7 +85,7 @@ you can specify placeholder value: ), )); -Note that `label_translation_parameters` of buttons are merged with those of its +Note that ``label_translation_parameters`` of buttons are merged with those of its parent. In other words the parent's translation parameters are available for children's buttons but can be overriden: diff --git a/reference/forms/types/options/attr_translation_parameters.rst.inc b/reference/forms/types/options/attr_translation_parameters.rst.inc index 362fd5f4820..f23aee36ee2 100644 --- a/reference/forms/types/options/attr_translation_parameters.rst.inc +++ b/reference/forms/types/options/attr_translation_parameters.rst.inc @@ -1,7 +1,7 @@ attr_translation_parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``array`` **default**: ``array()`` +**type**: ``array`` **default**: ``[]`` Some translated `attr`_ (``title`` and ``placeholder``) can contain :ref:`placeholders `. @@ -30,7 +30,7 @@ you can specify placeholder value: ] )); -Note that `attr_translation_parameters` of children fields are merged with those +Note that ``attr_translation_parameters`` of children fields are merged with those of its parent. In other words the parent's translation parameters are available for children but can be overriden: diff --git a/reference/forms/types/options/help_translation_parameters.rst.inc b/reference/forms/types/options/help_translation_parameters.rst.inc index cd0755c0cde..3a1138e9f1d 100644 --- a/reference/forms/types/options/help_translation_parameters.rst.inc +++ b/reference/forms/types/options/help_translation_parameters.rst.inc @@ -1,7 +1,7 @@ help_translation_parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``array`` **default**: ``array()`` +**type**: ``array`` **default**: ``[]`` Translated `help`_ can contain :ref:`placeholders `. @@ -26,7 +26,7 @@ you can specify placeholder value: ] )); -Note that `help_translation_parameters` of children fields are merged with those +Note that ``help_translation_parameters`` of children fields are merged with those of its parent. In other words the parent's translation parameters are available for children but can be overriden: diff --git a/reference/forms/types/options/label_translation_parameters.rst.inc b/reference/forms/types/options/label_translation_parameters.rst.inc index aec761841ce..269b52ff72f 100644 --- a/reference/forms/types/options/label_translation_parameters.rst.inc +++ b/reference/forms/types/options/label_translation_parameters.rst.inc @@ -1,7 +1,7 @@ label_translation_parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``array`` **default**: ``array()`` +**type**: ``array`` **default**: ``[]`` Translated `label`_, can contain :ref:`placeholders `. @@ -26,7 +26,7 @@ you can specify placeholder value: ] )); -Note that `label_translation_parameters` of children fields are merged with those +Note that ``label_translation_parameters`` of children fields are merged with those of its parent. In other words the parent's translation parameters are available for children but can be overriden: diff --git a/reference/forms/types/reset.rst b/reference/forms/types/reset.rst index 394e113cd82..b3d0e14db0a 100644 --- a/reference/forms/types/reset.rst +++ b/reference/forms/types/reset.rst @@ -51,7 +51,7 @@ as a key. This can be useful when you need to set a custom class for the button: label_translation_parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``array`` **default**: ``array()`` +**type**: ``array`` **default**: ``[]`` Translated `label`_ can contain :ref:`placeholders `. @@ -79,7 +79,7 @@ you can specify placeholder value: ), )); -Note that `label_translation_parameters` of resets are merged with those of its +Note that ``label_translation_parameters`` of resets are merged with those of its parent. In other words the parent's translation parameters are available for children's resets but can be overriden: diff --git a/reference/forms/types/submit.rst b/reference/forms/types/submit.rst index 3c2b741280e..541b2cbba77 100644 --- a/reference/forms/types/submit.rst +++ b/reference/forms/types/submit.rst @@ -64,7 +64,7 @@ as a key. This can be useful when you need to set a custom class for the button: label_translation_parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**type**: ``array`` **default**: ``array()`` +**type**: ``array`` **default**: ``[]`` Translated `label`_ can contain :ref:`placeholders `. @@ -92,7 +92,7 @@ you can specify placeholder value: ), )); -Note that `label_translation_parameters` of submits are merged with those of its +Note that ``label_translation_parameters`` of submits are merged with those of its parent. In other words the parent's translation parameters are available for children's submits but can be overriden: From f4597bfff930fbeb2a93f2caeb39c786cacc2cda Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 12 Feb 2019 07:35:11 +0100 Subject: [PATCH 015/499] format option deprecation for HTML 5 widgets --- reference/forms/types/date.rst | 5 +++++ reference/forms/types/datetime.rst | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index 0b240504c17..7031b6211dd 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -165,6 +165,11 @@ values for the year, month and day fields:: .. include:: /reference/forms/types/options/date_format.rst.inc +.. versionadded:: 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 5b9295c5885..ce756d19d40 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -133,6 +133,11 @@ 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`_. +.. versionadded:: 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 From af028003b9a6519e29d7f987192314e0fa111579 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 16 Feb 2019 11:31:13 +0100 Subject: [PATCH 016/499] fix type of the grouping option --- reference/forms/types/options/grouping.rst.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/options/grouping.rst.inc b/reference/forms/types/options/grouping.rst.inc index 4362678e339..0ebd339b2e8 100644 --- a/reference/forms/types/options/grouping.rst.inc +++ b/reference/forms/types/options/grouping.rst.inc @@ -1,7 +1,7 @@ grouping ~~~~~~~~ -**type**: ``integer`` **default**: ``false`` +**type**: ``boolean`` **default**: ``false`` This value is used internally as the ``NumberFormatter::GROUPING_USED`` value when using PHP's ``NumberFormatter`` class. Its documentation is From 2ea9797b2b6500bdcf94e927f4b4818beeeac0f6 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 16 Feb 2019 11:40:53 +0100 Subject: [PATCH 017/499] document the parent_form() Twig function --- form/form_customization.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/form/form_customization.rst b/form/form_customization.rst index 0aaa095ae6c..3334dfe1689 100644 --- a/form/form_customization.rst +++ b/form/form_customization.rst @@ -312,6 +312,18 @@ obvious (since it'll render the field for you). {{ form_rest(form) }} +parent_form(form_view) +...................... + +.. versionadded:: 4.3 + + The ``parent_form()`` 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 +when a child form is named ``parent``. + Tests ~~~~~ From 2d7709f6056dfad3bff8a3747b32c7507c1371fd Mon Sep 17 00:00:00 2001 From: Zan Baldwin Date: Tue, 19 Feb 2019 15:58:00 +0000 Subject: [PATCH 018/499] [DependencyInjection] Invokable Factory Services Document new invokable factories (and configurators) implemented in symfony/symfony#30255. --- service_container/configurators.rst | 72 +++++++++++++++++++++++++++++ service_container/factories.rst | 70 ++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/service_container/configurators.rst b/service_container/configurators.rst index b8b1a28f742..921c751909e 100644 --- a/service_container/configurators.rst +++ b/service_container/configurators.rst @@ -195,6 +195,78 @@ the service id and the method name: # old syntax configurator: ['@App\Mail\EmailConfigurator', configure] +.. _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 +route definitions can reference :ref:`invokable +controllers `. + +.. code-block:: yaml + + # app/config/services.yml + services: + # ... + + # Registers all 4 classes as services, including AppBundle\Mail\EmailConfigurator + AppBundle\: + resource: '../../src/AppBundle/*' + # ... + + # override the services to set the configurator + AppBundle\Mail\NewsletterManager: + configurator: '@AppBundle\Mail\EmailConfigurator' + + AppBundle\Mail\GreetingCardManager: + configurator: '@AppBundle\Mail\EmailConfigurator' + +.. code-block:: xml + + + + + + + + + + + + + + + + + + +.. code-block:: php + + // app/config/services.php + use AppBundle\Mail\GreetingCardManager; + use AppBundle\Mail\NewsletterManager; + use Symfony\Component\DependencyInjection\Definition; + use Symfony\Component\DependencyInjection\Reference; + + // Same as before + $definition = new Definition(); + + $definition->setAutowired(true); + + $this->registerClasses($definition, 'AppBundle\\', '../../src/AppBundle/*'); + + $container->getDefinition(NewsletterManager::class) + ->setConfigurator(new Reference(EmailConfigurator::class)); + + $container->getDefinition(GreetingCardManager::class) + ->setConfigurator(new Reference(EmailConfigurator::class)); + That's it! When requesting the ``App\Mail\NewsletterManager`` or ``App\Mail\GreetingCardManager`` service, the created instance will first be passed to the ``EmailConfigurator::configure()`` method. diff --git a/service_container/factories.rst b/service_container/factories.rst index 39524ccc80c..37a30f29e21 100644 --- a/service_container/factories.rst +++ b/service_container/factories.rst @@ -157,6 +157,76 @@ Configuration of the service container then looks like this: # old syntax factory: ['@App\Email\NewsletterManagerFactory', createNewsletterManager] +.. _factories-invokable: + +Suppose you now change your factory method to ``__invoke()`` so that your +factory service can be used as a callback:: + + class InvokableNewsletterManagerFactory + { + public function __invoke() + { + $newsletterManager = new NewsletterManager(); + + // ... + + return $newsletterManager; + } + } + +.. 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 route definitions can reference :ref:`invokable +controllers `. + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/services.yml + + services: + # ... + + AppBundle\Email\NewsletterManager: + class: AppBundle\Email\NewsletterManager + factory: '@AppBundle\Email\NewsletterManagerFactory' + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // app/config/services.php + + use AppBundle\Email\NewsletterManager; + use AppBundle\Email\NewsletterManagerFactory; + use Symfony\Component\DependencyInjection\Reference; + + // ... + $container->register(NewsletterManager::class, NewsletterManager::class) + ->setFactory(new Reference(NewsletterManagerFactory::class)); + .. _factories-passing-arguments-factory-method: Passing Arguments to the Factory Method From 0fbef778e0de05447421c78da380a6d1c2e42e4f Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 22 Feb 2019 22:07:17 +0100 Subject: [PATCH 019/499] document the deprecation of the role classes --- components/security/authorization.rst | 24 +++------------- security/impersonating_user.rst | 40 +++++++++++++-------------- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/components/security/authorization.rst b/components/security/authorization.rst index 4bac0b42c74..33e2efb9b9c 100644 --- a/components/security/authorization.rst +++ b/components/security/authorization.rst @@ -19,7 +19,7 @@ by an instance of :class:`Symfony\\Component\\Security\\Core\\Authorization\\Acc 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::getRoles` + 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 @@ -127,7 +127,7 @@ RoleVoter The :class:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleVoter` supports attributes starting with ``ROLE_`` and grants access to the user when the required ``ROLE_*`` attributes can all be found in the array of -roles returned by the token's :method:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface::getRoles` +roles returned by the token's :method:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface::getRoleNames` method:: use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter; @@ -167,24 +167,8 @@ role:: Roles ----- -Roles are objects that give expression to a certain right the user has. The only -requirement is that they must define a ``getRole()`` method that returns a -string representation of the role itself. To do so, you can optionally extend -from the default :class:`Symfony\\Component\\Security\\Core\\Role\\Role` class, -which returns its first constructor argument in this method:: - - use Symfony\Component\Security\Core\Role\Role; - - $role = new Role('ROLE_ADMIN'); - - // shows 'ROLE_ADMIN' - var_dump($role->getRole()); - -.. note:: - - Most authentication tokens extend from :class:`Symfony\\Component\\Security\\Core\\Authentication\\Token\\AbstractToken`, - which means that the roles given to its constructor will be - automatically converted from strings to these simple ``Role`` objects. +Roles are strings that give expression to a certain right the user has. The only +requirement is that they must start with the ``ROLE_`` prefix. Using the Decision Manager -------------------------- diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst index 354be149011..d7cb59046ee 100644 --- a/security/impersonating_user.rst +++ b/security/impersonating_user.rst @@ -98,11 +98,17 @@ 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. Use the following snippet to iterate -over the user's roles until you find one that is a ``SwitchUserRole`` object:: +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 +following snippet to obtain the original token which gives you access to +the impersonator user:: - use Symfony\Component\Security\Core\Role\SwitchUserRole; + use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken use Symfony\Component\Security\Core\Security; // ... @@ -119,14 +125,13 @@ over the user's roles until you find one that is a ``SwitchUserRole`` object:: { // ... - if ($this->security->isGranted('ROLE_PREVIOUS_ADMIN')) { - foreach ($this->security->getToken()->getRoles() as $role) { - if ($role instanceof SwitchUserRole) { - $impersonatorUser = $role->getSource()->getUser(); - break; - } - } + $token = $this->security->getToken(); + + if ($token instanceof SwitchUserToken) { + $impersonatorUser = $token->getOriginalToken()->getUser(); } + + // ... } } @@ -221,24 +226,17 @@ Create the voter class:: } if (in_array('ROLE_CUSTOMER', $subject->getRoles()) - && $this->hasSwitchToCustomerRole($token)) { + && in_array('ROLE_SWITCH_TO_CUSTOMER', $token->getRoleNames(), true)) { return true; } return false; } + } - private function hasSwitchToCustomerRole(TokenInterface $token) - { - foreach ($token->getRoles() as $role) { - if ($role->getRole() === 'ROLE_SWITCH_TO_CUSTOMER') { - return true; - } - } +.. versionadded:: 4.3 - return false; - } - } + 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`` From f9e355985489ada1893d1f6c4e4f5fbac4603295 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 23 Feb 2019 11:02:37 +0100 Subject: [PATCH 020/499] rename parent_form() to form_parent() --- form/form_customization.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/form/form_customization.rst b/form/form_customization.rst index e985d0d4a43..3ecedf61d6c 100644 --- a/form/form_customization.rst +++ b/form/form_customization.rst @@ -312,12 +312,12 @@ obvious (since it'll render the field for you). {{ form_rest(form) }} -parent_form(form_view) +form_parent(form_view) ...................... .. versionadded:: 4.3 - The ``parent_form()`` function was introduced in Symfony 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 From 29c0fc16ae48cf59767cfe7b2289757b9c375d23 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 26 Feb 2019 10:51:00 +0100 Subject: [PATCH 021/499] Minor tweaks --- components/security/authorization.rst | 6 ++++-- security/impersonating_user.rst | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/security/authorization.rst b/components/security/authorization.rst index 33e2efb9b9c..83860b25060 100644 --- a/components/security/authorization.rst +++ b/components/security/authorization.rst @@ -167,8 +167,10 @@ role:: Roles ----- -Roles are strings that give expression to a certain right the user has. The only -requirement is that they must start with the ``ROLE_`` prefix. +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 -------------------------- diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst index e679000a2fa..edaa4af043f 100644 --- a/security/impersonating_user.rst +++ b/security/impersonating_user.rst @@ -98,7 +98,7 @@ to show a link to exit impersonation: Finding the Original User ------------------------- -versionadded:: 4.3 +.. versionadded:: 4.3 The ``SwitchUserToken`` class was introduced in Symfony 4.3. From 0c136fafe4c66e2aa1dd89194499e12029d67532 Mon Sep 17 00:00:00 2001 From: Anton Chernikov Date: Tue, 26 Feb 2019 13:20:02 +0300 Subject: [PATCH 022/499] new valid card scheme MIR --- reference/constraints/CardScheme.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/reference/constraints/CardScheme.rst b/reference/constraints/CardScheme.rst index 299b45cdda2..1f0ae7a7ebf 100644 --- a/reference/constraints/CardScheme.rst +++ b/reference/constraints/CardScheme.rst @@ -119,6 +119,7 @@ Valid values are: * ``LASER`` * ``MAESTRO`` * ``MASTERCARD`` +* ``MIR`` * ``UATP`` * ``VISA`` From ef324dc7a7b86240575a875dfc2dfd14ed26e5ec Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 26 Feb 2019 12:10:57 +0100 Subject: [PATCH 023/499] Fixed a minor PHP issue --- security/impersonating_user.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst index edaa4af043f..f6d05e78769 100644 --- a/security/impersonating_user.rst +++ b/security/impersonating_user.rst @@ -108,7 +108,7 @@ stored in the token storage will be a ``SwitchUserToken`` instance. Use the following snippet to obtain the original token which gives you access to the impersonator user:: - use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken + use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Security; // ... From d89122c154d56ad1b5dcabbd96da4b4293900c43 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Wed, 27 Feb 2019 08:26:21 +0100 Subject: [PATCH 024/499] Update service_container_parameters.rst --- routing/service_container_parameters.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/routing/service_container_parameters.rst b/routing/service_container_parameters.rst index 35e248232e7..940c1550c69 100644 --- a/routing/service_container_parameters.rst +++ b/routing/service_container_parameters.rst @@ -138,3 +138,7 @@ path): For parameter handling within a Dependency Injection Class see :doc:`/configuration/using_parameters_in_dic`. + +.. versionadded:: 4.3 + + Support for boolean container parameters was introduced in Symfony 4.3. From bc5ac2806ea527cf4cad330a757012bbf1ac3e1c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 16 Feb 2019 11:21:27 +0100 Subject: [PATCH 025/499] document the NumberType html5 option --- reference/forms/types/number.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/reference/forms/types/number.rst b/reference/forms/types/number.rst index 4d77428e171..3fad6c65e52 100644 --- a/reference/forms/types/number.rst +++ b/reference/forms/types/number.rst @@ -12,6 +12,7 @@ that you want to use for your number. | Rendered as | ``input`` ``text`` field | +-------------+----------------------------------------------------------------------+ | Options | - `grouping`_ | +| | - `html5`_ | | | - `scale`_ | | | - `rounding_mode`_ | +-------------+----------------------------------------------------------------------+ @@ -46,6 +47,18 @@ Field Options .. include:: /reference/forms/types/options/grouping.rst.inc +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. + scale ~~~~~ From 01ea746e071dc44caeee32b914423f3e419ffe27 Mon Sep 17 00:00:00 2001 From: zairig imad Date: Sun, 16 Sep 2018 11:46:58 +0200 Subject: [PATCH 026/499] [Validator] Add new json Validator Documentation --- reference/constraints.rst | 1 + reference/constraints/Json.rst | 99 +++++++++++++++++++++++++++++++ reference/constraints/map.rst.inc | 1 + 3 files changed, 101 insertions(+) create mode 100644 reference/constraints/Json.rst diff --git a/reference/constraints.rst b/reference/constraints.rst index b64c8fbdbaa..d81a4eefd37 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -19,6 +19,7 @@ Validation Constraints Reference constraints/Regex constraints/Ip constraints/Uuid + constraints/Json constraints/EqualTo constraints/NotEqualTo diff --git a/reference/constraints/Json.rst b/reference/constraints/Json.rst new file mode 100644 index 00000000000..4b722ca1064 --- /dev/null +++ b/reference/constraints/Json.rst @@ -0,0 +1,99 @@ +Json + +Validates that a value is valid ``json``. Specifically, this checks to see if +the value is a valid ``json`` or not. + ++----------------+-----------------------------------------------------------------------+ +| Applies to | :ref:`property or method ` | ++----------------+-----------------------------------------------------------------------+ +| Options | - `message`_ | +| | - `payload`_ | ++----------------+-----------------------------------------------------------------------+ +| Class | :class:`Symfony\\Component\\Validator\\Constraints\\Json` | ++----------------+-----------------------------------------------------------------------+ +| Validator | :class:`Symfony\\Component\\Validator\\Constraints\\JsonValidator` | ++----------------+-----------------------------------------------------------------------+ + +Basic Usage +----------- + +The ``Json`` constraint can be applied to a property or a "getter" method, +but is most commonly useful in the latter case. For example, suppose that +you want to guarantee that some ``jsonString`` property is valid JSON. + +.. configuration-block:: + + .. code-block:: php-annotations + + // 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 + App\Entity\Book: + properties: + chapters: + - Json: + message: You've entered an invalid Json. + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/Book.php + namespace App\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Book + { + private $chapters; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('chapters', new Assert\Json(array( + 'message' => 'You\'ve entered an invalid Json.', + ))); + } + } + +Options +------- + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be valid JSON.`` + +This message is shown if the underlying data is not a valid JSON. + +.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index 03d573559ee..655ef1723b3 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -21,6 +21,7 @@ String Constraints * :doc:`Regex ` * :doc:`Ip ` * :doc:`Uuid` +* :doc:`Json` Comparison Constraints ~~~~~~~~~~~~~~~~~~~~~~ From 7c9f6315d6e06e209dfc1b590f8643bafd70419f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 4 Mar 2019 12:51:41 +0100 Subject: [PATCH 027/499] Minor tweaks --- reference/constraints/Json.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/reference/constraints/Json.rst b/reference/constraints/Json.rst index 4b722ca1064..c993881003e 100644 --- a/reference/constraints/Json.rst +++ b/reference/constraints/Json.rst @@ -1,7 +1,7 @@ Json +==== -Validates that a value is valid ``json``. Specifically, this checks to see if -the value is a valid ``json`` or not. +Validates that a value has valid `JSON`_ syntax. +----------------+-----------------------------------------------------------------------+ | Applies to | :ref:`property or method ` | @@ -17,9 +17,7 @@ the value is a valid ``json`` or not. Basic Usage ----------- -The ``Json`` constraint can be applied to a property or a "getter" method, -but is most commonly useful in the latter case. For example, suppose that -you want to guarantee that some ``jsonString`` property is valid JSON. +The ``Json`` constraint can be applied to a property or a "getter" method: .. configuration-block:: @@ -60,7 +58,7 @@ you want to guarantee that some ``jsonString`` property is valid JSON. - + @@ -94,6 +92,8 @@ message **type**: ``string`` **default**: ``This value should be valid JSON.`` -This message is shown if the underlying data is not a valid JSON. +This message is shown if the underlying data is not a valid JSON value. .. include:: /reference/constraints/_payload-option.rst.inc + +.. _`JSON`: https://en.wikipedia.org/wiki/JSON From 0a42ca714cd2c4b889779e13fcc25b549168e311 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 6 Mar 2019 09:34:05 +0100 Subject: [PATCH 028/499] Minor tweaks --- reference/forms/types/button.rst | 78 +++++-------------- .../attr_translation_parameters.rst.inc | 71 ++++------------- .../help_translation_parameters.rst.inc | 62 +++------------ .../label_translation_parameters.rst.inc | 62 +++------------ reference/forms/types/reset.rst | 66 +++------------- reference/forms/types/submit.rst | 66 +++------------- 6 files changed, 79 insertions(+), 326 deletions(-) diff --git a/reference/forms/types/button.rst b/reference/forms/types/button.rst index 4d0459b489c..5ce297acba8 100644 --- a/reference/forms/types/button.rst +++ b/reference/forms/types/button.rst @@ -10,11 +10,11 @@ A simple, non-responsive button. | Rendered as | ``button`` tag | +----------------------+----------------------------------------------------------------------+ | Inherited | - `attr`_ | -| options | - `disabled`_ | +| options | - `attr_translation_parameters`_ | +| | - `disabled`_ | | | - `label`_ | -| | - `translation_domain`_ | | | - `label_translation_parameters`_ | -| | - `attr_translation_parameters`_ | +| | - `translation_domain`_ | +----------------------+----------------------------------------------------------------------+ | Parent type | none | +----------------------+----------------------------------------------------------------------+ @@ -59,77 +59,37 @@ label_translation_parameters **type**: ``array`` **default**: ``[]`` -Translated `label`_ can contain -:ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. +.. 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. Given this translation message: .. code-block:: yaml # translations/messages.en.yml - form.order.submit_to_company: Send an order to %company% + form.order.submit_to_company: 'Send an order to %company%' -you can specify placeholder value: +You can specify the placeholder values as follows: .. code-block:: php use Symfony\Component\Form\Extension\Core\Type\ButtonType; // ... - $builder->add('send', ButtonType::class, array( + $builder->add('send', ButtonType::class, [ 'label' => 'form.order.submit_to_company', - 'label_translation_parameters' => array( + 'label_translation_parameters' => [ '%company%' => 'ACME Inc.', - ), - )); - -Note that ``label_translation_parameters`` of buttons are merged with those of its -parent. In other words the parent's translation parameters are available for -children's buttons but can be overriden: - -.. code-block:: php - - // App/Controller/OrderController.php - use App\Form\OrderType; - // ... - - $form = $this->createForm(OrderType::class, $order, array( - // available to all children, grandchildren and so on. - 'label_translation_parameters' => array( - '%company%' => 'ACME', - ), - )); - -.. code-block:: php - - // App/Form/OrderType.php - use Symfony\Component\Form\Extension\Core\Type\ButtonType; - // ... - - $builder->add('send', ButtonType::class, array( - 'label' => 'form.order.submit_to_company', - // Value of parent's 'label_translation_parameters' will be merged with - // this field's empty 'label_translation_parameters'. - // array('%company%' => 'ACME') will be used to translate this label. - )); - -.. code-block:: php - - // App/Form/OrderType.php - use Symfony\Component\Form\Extension\Core\Type\ButtonType; - // ... + ], + ]); - $builder->add('send', ButtonType::class, array( - 'label' => 'form.order.submit_to_company', - 'label_translation_parameters' => array( - '%company%' => 'American Company Making Everything', - ), - // Value of parent's 'label_translation_parameters' will be merged with - // this button's 'label_translation_parameters'. - // array('%company%' => 'American Company Making Everything') - // will be used to translate this label. - )); +The ``label_translation_parameters`` option of buttons is merged with the same +option of its parents, so buttons can reuse and/or override any of the parent +placeholders. .. include:: /reference/forms/types/options/attr_translation_parameters.rst.inc diff --git a/reference/forms/types/options/attr_translation_parameters.rst.inc b/reference/forms/types/options/attr_translation_parameters.rst.inc index f23aee36ee2..bda010127c6 100644 --- a/reference/forms/types/options/attr_translation_parameters.rst.inc +++ b/reference/forms/types/options/attr_translation_parameters.rst.inc @@ -3,20 +3,24 @@ attr_translation_parameters **type**: ``array`` **default**: ``[]`` -Some translated `attr`_ (``title`` and ``placeholder``) can -contain :ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. +.. 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 +option defines the values used to replace those placeholders. Given this translation message: .. code-block:: yaml # translations/messages.en.yml - form.order.id.placeholder: Enter unique identifier of the order to %company% - form.order.id.title: This will be the reference in communications with %company% + form.order.id.placeholder: 'Enter unique identifier of the order to %company%' + form.order.id.title: 'This will be the reference in communications with %company%' -you can specify placeholder value: +You can specify the placeholder values as follows: .. code-block:: php @@ -30,53 +34,6 @@ you can specify placeholder value: ] )); -Note that ``attr_translation_parameters`` of children fields are merged with those -of its parent. In other words the parent's translation parameters are available -for children but can be overriden: - -.. code-block:: php - - // App/Controller/OrderController.php - use App\Form\OrderType; - // ... - - $form = $this->createForm(OrderType::class, $order, array( - // available to all children, grandchildren and so on. - 'attr_translation_parameters' => array( - '%company%' => 'ACME', - ), - )); - - .. code-block:: php - - // App/Form/OrderType.php - // ... - - $builder->add('id', null, array( - 'attr' => array( - 'placeholder' => 'form.order.id.placeholder', - 'title' => 'form.order.id.title', - ), - // Value of parent's 'attr_translation_parameters' will be merged with - // this field's empty 'attr_translation_parameters'. - // array('%company%' => 'ACME') will be used to translate 'placeholder' and 'title'. - )); - - .. code-block:: php - - // App/Form/OrderType.php - // ... - - $builder->add('id', null, array( - 'attr' => array( - 'placeholder' => 'form.order.id.placeholder', - 'title' => 'form.order.id.title', - ), - 'attr_translation_parameters' => array( - '%company%' => 'American Company Making Everything', - ), - // Value of parent's 'attr_translation_parameters' will be merged with - // this field's 'attr_translation_parameters'. - // array('%company%' => 'American Company Making Everything') - // will be used to translate 'placeholder' and 'title'. - )); +The ``attr_translation_parameters`` option of children fields is 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/help_translation_parameters.rst.inc b/reference/forms/types/options/help_translation_parameters.rst.inc index 3a1138e9f1d..44723597127 100644 --- a/reference/forms/types/options/help_translation_parameters.rst.inc +++ b/reference/forms/types/options/help_translation_parameters.rst.inc @@ -3,19 +3,22 @@ help_translation_parameters **type**: ``array`` **default**: ``[]`` -Translated `help`_ can -contain :ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. +.. 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. Given this translation message: .. code-block:: yaml # translations/messages.en.yml - form.order.id.help: This will be the reference in communications with %company% + form.order.id.help: 'This will be the reference in communications with %company%' -you can specify placeholder value: +You can specify the placeholder values as follows: .. code-block:: php @@ -26,47 +29,6 @@ you can specify placeholder value: ] )); -Note that ``help_translation_parameters`` of children fields are merged with those -of its parent. In other words the parent's translation parameters are available -for children but can be overriden: - -.. code-block:: php - - // App/Controller/OrderController.php - use App\Form\OrderType; - // ... - - $form = $this->createForm(OrderType::class, $order, array( - // available to all children, grandchildren and so on. - 'help_translation_parameters' => array( - '%company%' => 'ACME', - ), - )); - - .. code-block:: php - - // App/Form/OrderType.php - // ... - - $builder->add('id', null, array( - 'help' => 'form.order.id.help', - // Value of parent's 'help_translation_parameters' will be merged with - // this field's empty 'help_translation_parameters'. - // array('%company%' => 'ACME') will be used to translate 'help'. - )); - - .. code-block:: php - - // App/Form/OrderType.php - // ... - - $builder->add('id', null, array( - 'help' => 'form.order.id.help', - 'help_translation_parameters' => array( - '%company%' => 'American Company Making Everything', - ), - // Value of parent's 'help_translation_parameters' will be merged with - // this field's 'help_translation_parameters'. - // array('%company%' => 'American Company Making Everything') - // will be used to translate 'help'. - )); +The ``help_translation_parameters`` option of children fields is 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/label_translation_parameters.rst.inc b/reference/forms/types/options/label_translation_parameters.rst.inc index 269b52ff72f..f7903c5a473 100644 --- a/reference/forms/types/options/label_translation_parameters.rst.inc +++ b/reference/forms/types/options/label_translation_parameters.rst.inc @@ -3,19 +3,22 @@ label_translation_parameters **type**: ``array`` **default**: ``[]`` -Translated `label`_, can -contain :ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. +.. 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. Given this translation message: .. code-block:: yaml # translations/messages.en.yml - form.order.id: Identifier of the order to %company% + form.order.id: 'Identifier of the order to %company%' -you can specify placeholder value: +You can specify the placeholder values as follows: .. code-block:: php @@ -26,47 +29,6 @@ you can specify placeholder value: ] )); -Note that ``label_translation_parameters`` of children fields are merged with those -of its parent. In other words the parent's translation parameters are available -for children but can be overriden: - -.. code-block:: php - - // App/Controller/OrderController.php - use App\Form\OrderType; - // ... - - $form = $this->createForm(OrderType::class, $order, array( - // available to all children, grandchildren and so on. - 'label_translation_parameters' => array( - '%company%' => 'ACME', - ), - )); - - .. code-block:: php - - // App/Form/OrderType.php - // ... - - $builder->add('id', null, array( - 'label' => 'form.order.id', - // Value of parent's 'label_translation_parameters' will be merged with - // this field's empty 'label_translation_parameters'. - // array('%company%' => 'ACME') will be used to translate this label. - )); - - .. code-block:: php - - // App/Form/OrderType.php - // ... - - $builder->add('id', null, array( - 'label' => 'form.order.id', - 'label_translation_parameters' => array( - '%company%' => 'American Company Making Everything', - ), - // Value of parent's 'label_translation_parameters' will be merged with - // this field's 'label_translation_parameters'. - // array('%company%' => 'American Company Making Everything') - // will be used to translate this label. - )); +The ``label_translation_parameters`` option of children fields is 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/reset.rst b/reference/forms/types/reset.rst index b3d0e14db0a..a4b7642b5a6 100644 --- a/reference/forms/types/reset.rst +++ b/reference/forms/types/reset.rst @@ -10,11 +10,11 @@ A button that resets all fields to their original values. | Rendered as | ``input`` ``reset`` tag | +----------------------+---------------------------------------------------------------------+ | Inherited | - `attr`_ | -| options | - `disabled`_ | +| options | - `attr_translation_parameters`_ | +| | - `disabled`_ | | | - `label`_ | -| | - `translation_domain`_ | | | - `label_translation_parameters`_ | -| | - `attr_translation_parameters`_ | +| | - `translation_domain`_ | +----------------------+---------------------------------------------------------------------+ | Parent type | :doc:`ButtonType ` | +----------------------+---------------------------------------------------------------------+ @@ -53,19 +53,18 @@ label_translation_parameters **type**: ``array`` **default**: ``[]`` -Translated `label`_ can contain -:ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. +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. Given this translation message: .. code-block:: yaml # translations/messages.en.yml - form.order.reset: Reset an order to %company% + form.order.reset: 'Reset an order to %company%' -you can specify placeholder value: +You can specify the placeholder values as follows: .. code-block:: php @@ -79,51 +78,8 @@ you can specify placeholder value: ), )); -Note that ``label_translation_parameters`` of resets are merged with those of its -parent. In other words the parent's translation parameters are available for -children's resets but can be overriden: - -.. code-block:: php - - // App/Controller/OrderController.php - use App\Form\OrderType; - // ... - - $form = $this->createForm(OrderType::class, $order, array( - // available to all children, grandchildren and so on. - 'label_translation_parameters' => array( - '%company%' => 'ACME', - ), - )); - -.. code-block:: php - - // App/Form/OrderType.php - use Symfony\Component\Form\Extension\Core\Type\ResetType; - // ... - - $builder->add('send', ResetType::class, array( - 'label' => 'form.order.reset', - // Value of parent's 'label_translation_parameters' will be merged with - // this field's empty 'label_translation_parameters'. - // array('%company%' => 'ACME') will be used to translate this label. - )); - -.. code-block:: php - - // App/Form/OrderType.php - use Symfony\Component\Form\Extension\Core\Type\ResetType; - // ... - - $builder->add('send', ResetType::class, array( - 'label' => 'form.order.reset', - 'label_translation_parameters' => array( - '%company%' => 'American Company Making Everything', - ), - // Value of parent's 'label_translation_parameters' will be merged with - // this reset's 'label_translation_parameters'. - // array('%company%' => 'American Company Making Everything') - // will be passed to translate this label. - )); +The ``label_translation_parameters`` option of buttons is merged with the same +option of its parents, so buttons can reuse and/or override any of the parent +placeholders. .. include:: /reference/forms/types/options/attr_translation_parameters.rst.inc diff --git a/reference/forms/types/submit.rst b/reference/forms/types/submit.rst index 541b2cbba77..7e1bac1bfb1 100644 --- a/reference/forms/types/submit.rst +++ b/reference/forms/types/submit.rst @@ -10,12 +10,12 @@ A submit button. | Rendered as | ``button`` ``submit`` tag | +----------------------+----------------------------------------------------------------------+ | Inherited | - `attr`_ | -| options | - `disabled`_ | +| options | - `attr_translation_parameters`_ | +| | - `disabled`_ | | | - `label`_ | | | - `label_format`_ | -| | - `translation_domain`_ | | | - `label_translation_parameters`_ | -| | - `attr_translation_parameters`_ | +| | - `translation_domain`_ | | | - `validation_groups`_ | +----------------------+----------------------------------------------------------------------+ | Parent type | :doc:`ButtonType` | @@ -66,19 +66,18 @@ label_translation_parameters **type**: ``array`` **default**: ``[]`` -Translated `label`_ can contain -:ref:`placeholders `. -This option allows you to pass an array of parameters in order to replace -placeholders with actual values. +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. Given this translation message: .. code-block:: yaml # translations/messages.en.yml - form.order.submit_to_company: Send an order to %company% + form.order.submit_to_company: 'Send an order to %company%' -you can specify placeholder value: +You can specify the placeholder values as follows: .. code-block:: php @@ -92,52 +91,9 @@ you can specify placeholder value: ), )); -Note that ``label_translation_parameters`` of submits are merged with those of its -parent. In other words the parent's translation parameters are available for -children's submits but can be overriden: - -.. code-block:: php - - // App/Controller/OrderController.php - use App\Form\OrderType; - // ... - - $form = $this->createForm(OrderType::class, $order, array( - // available to all children, grandchildren and so on. - 'label_translation_parameters' => array( - '%company%' => 'ACME', - ), - )); - -.. code-block:: php - - // App/Form/OrderType.php - use Symfony\Component\Form\Extension\Core\Type\SubmitType; - // ... - - $builder->add('send', SubmitType::class, array( - 'label' => 'form.order.submit_to_company', - // Value of parent's 'label_translation_parameters' will be merged with - // this field's empty 'label_translation_parameters'. - // array('%company%' => 'ACME') will be used to translate this label. - )); - -.. code-block:: php - - // App/Form/OrderType.php - use Symfony\Component\Form\Extension\Core\Type\SubmitType; - // ... - - $builder->add('send', SubmitType::class, array( - 'label' => 'form.order.submit_to_company', - 'label_translation_parameters' => array( - '%company%' => 'American Company Making Everything', - ), - // Value of parent's 'label_translation_parameters' will be merged with - // this submit's 'label_translation_parameters'. - // array('%company%' => 'American Company Making Everything') - // will be passed to translate this label. - )); +The ``label_translation_parameters`` option of buttons is merged with the same +option of its parents, so buttons can reuse and/or override any of the parent +placeholders. .. include:: /reference/forms/types/options/attr_translation_parameters.rst.inc From e70b0df1055326fc5e9853383b6d3aabef5e6862 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 6 Mar 2019 11:20:48 +0100 Subject: [PATCH 029/499] Re-added the allowNull option --- reference/constraints/NotBlank.rst | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index 0c5ee1db9bf..e4d378c1606 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -2,13 +2,15 @@ NotBlank ======== Validates that a value is not blank - meaning not equal to a blank string, -a blank array, ``false`` or ``null``. To check that a value is not equal to -``null``, see the :doc:`/reference/constraints/NotNull` constraint. +a blank array, ``false`` or ``null`` (null behavior is configurable). To check +that a value is not equal to ``null``, see the +:doc:`/reference/constraints/NotNull` constraint. +----------------+------------------------------------------------------------------------+ | Applies to | :ref:`property or method ` | +----------------+------------------------------------------------------------------------+ -| Options | - `message`_ | +| Options | - `allowNull`_ | +| | - `message`_ | | | - `payload`_ | +----------------+------------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Validator\\Constraints\\NotBlank` | @@ -81,6 +83,18 @@ class were not blank, you could do the following: Options ------- +allowNull +~~~~~~~~~ + +**type**: ``bool`` **default**: ``false`` + +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. + message ~~~~~~~ From 334ee9944dfc4e1037c14f395402a6921eb488cd Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 6 Mar 2019 12:04:30 +0100 Subject: [PATCH 030/499] Readded all 4.3 features --- components/console/helpers/progressbar.rst | 27 ++++++++++ components/dom_crawler.rst | 23 +++++++- configuration/external_parameters.rst | 53 ++++++++++++++++++ console/coloring.rst | 17 ++++++ form/create_custom_field_type.rst | 6 +++ form/form_themes.rst | 26 +++++++++ routing.rst | 8 +++ security/csrf.rst | 9 ++++ service_container/alias_private.rst | 63 ++++++++++++++++++++++ 9 files changed, 230 insertions(+), 2 deletions(-) diff --git a/components/console/helpers/progressbar.rst b/components/console/helpers/progressbar.rst index 81fc8e4c489..bf832b3131e 100644 --- a/components/console/helpers/progressbar.rst +++ b/components/console/helpers/progressbar.rst @@ -95,6 +95,33 @@ that the progress bar display is refreshed with a 100% completion. :method:`Symfony\\Component\\Console\\Helper\\ProgressBar::display` to show the progress bar again. +If the progress information is stored in an iterable variable (such as an array +or a PHP generator) you can use the +:method:`Symfony\\Component\\Console\\Helper\\ProgressBar::iterate` method, +which starts, advances and finishes the progress bar automatically:: + + use Symfony\Component\Console\Helper\ProgressBar; + + $progressBar = new ProgressBar($output); + + // $iterable can be for example an array ([1, 2, 3, ...]) or a generator + // $iterable = function () { yield 1; yield 2; ... }; + foreach ($progressBar->iterate($iterable) as $value) { + // ... do some work + } + +If ``$iterable = [1, 2]``, the previous code will output the following: + +.. code-block:: terminal + + 0/2 [>---------------------------] 0% + 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/dom_crawler.rst b/components/dom_crawler.rst index d1873b59d76..e0f573c5393 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -204,6 +204,13 @@ Access the value of the first node of the current selection:: // if the node does not exist, calling to text() will result in an exception $message = $crawler->filterXPath('//body/p')->text(); + // 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'); @@ -212,12 +219,17 @@ Extract attribute and/or node values from the list of nodes:: $attributes = $crawler ->filterXpath('//body/p') - ->extract(['_text', 'class']) + ->extract(['_name', '_text', 'class']) ; .. note:: - Special attribute ``_text`` represents a node value. + 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:: @@ -297,6 +309,13 @@ and :phpclass:`DOMNode` objects:: // if the node does not exist, calling to html() will result in an exception $html = $crawler->html(); + // 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/configuration/external_parameters.rst b/configuration/external_parameters.rst index 96a0421615d..5f2cdd3a83b 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -446,6 +446,15 @@ Symfony provides the following env var processors: 'auth' => '%env(file:AUTH_FILE)%', ]); +``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: @@ -484,6 +493,50 @@ Symfony provides the following env var processors: $container->setParameter('env(SECRETS_FILE)', '/opt/application/.secrets.json'); $container->setParameter('database_password', '%env(key:database_password:json:file:SECRETS_FILE)%'); +``env(default:fallback_param:BAR)`` + Retrieves the value of the parameter ``fallback_param`` when the ``BAR`` env + var is not available: + + .. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + parameters: + # if PRIVATE_KEY is not a valid file path, the content of raw_key is returned + private_key: '%env(default:raw_key:file:PRIVATE_KEY)%' + raw_key: '%env(PRIVATE_KEY)%' + + .. code-block:: xml + + + + + + + %env(default:raw_key:file:PRIVATE_KEY)% + %env(PRIVATE_KEY)% + + + + .. code-block:: php + + // config/services.php + + // if PRIVATE_KEY is not a valid file path, the content of raw_key is returned + $container->setParameter('private_key', '%env(default:raw_key:file:PRIVATE_KEY)%'); + $container->setParameter('raw_key', '%env(PRIVATE_KEY)%'); + + .. versionadded:: 4.3 + + The ``default`` 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 a12cb29af96..b9a65cefc1b 100644 --- a/console/coloring.rst +++ b/console/coloring.rst @@ -74,8 +74,25 @@ You can also set these colors and options directly inside the tag name:: or use the :method:`Symfony\\Component\\Console\\Formatter\\OutputFormatter::escape` method to escape all the tags included in the given string. +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:: + + $output->writeln('Symfony Homepage'); + +If your terminal belongs to the `list of terminal emulators that support links`_ +you can click on the *"Symfony Homepage"* text to open its URL in your default +browser. Otherwise, you'll see *"Symfony Homepage"* as regular text and the URL +will be lost. + .. _Cmder: http://cmder.net/ .. _ConEmu: https://conemu.github.io/ .. _ANSICON: https://github.com/adoxa/ansicon/releases .. _Mintty: https://mintty.github.io/ .. _Hyper: https://hyper.is/ +.. _`list of terminal emulators that support links`: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda diff --git a/form/create_custom_field_type.rst b/form/create_custom_field_type.rst index 2e461647cef..a55113c2822 100644 --- a/form/create_custom_field_type.rst +++ b/form/create_custom_field_type.rst @@ -99,6 +99,12 @@ The goal of this field was to extend the choice type to enable selection of the shipping type. This is achieved by fixing the ``choices`` to a list of available shipping options. +.. tip:: + + If the purpose of this new form type was to customize the rendering of some + fields only, skip this step and use ``block_name`` or ``block_prefix`` options + instead to :ref:`define a custom form fragment name `. + .. tip:: Run the following command to verify that the form type was successfully diff --git a/form/form_themes.rst b/form/form_themes.rst index ee125ea1c89..08f21397614 100644 --- a/form/form_themes.rst +++ b/form/form_themes.rst @@ -275,6 +275,32 @@ form. You can also define this value explicitly with the ``block_name`` option:: In this example, the fragment name will be ``_product_custom_name_widget`` instead of the default ``_product_name_widget``. +.. _form-fragment-custom-naming: + +Custom Fragment Naming for Individual Fields +............................................ + +The ``block_prefix`` option allows form fields to define their own custom +fragment name. This is mostly useful to customize some instances of the same +field without having to :doc:`create a custom form type `:: + + use Symfony\Component\Form\Extension\Core\Type\TextType; + use Symfony\Component\Form\FormBuilderInterface; + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add('name', TextType::class, array( + 'block_prefix' => 'wrapped_text', + )); + } + +.. versionadded:: 4.3 + + The ``block_prefix`` option was introduced in Symfony 4.3. + +Now you can use ``wrapped_text_row``, ``wrapped_text_widget``, etc. as the block +names. + .. _form-custom-prototype: Fragment Naming for Collections diff --git a/routing.rst b/routing.rst index 6355bb3dd63..10e708d829e 100644 --- a/routing.rst +++ b/routing.rst @@ -511,6 +511,14 @@ So how can you make ``blog_list`` once again match when the user visits Now, when the user visits ``/blog``, the ``blog_list`` route will match and ``$page`` will default to a value of ``1``. +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 diff --git a/security/csrf.rst b/security/csrf.rst index b5e5e5f7a26..1cb195045b6 100644 --- a/security/csrf.rst +++ b/security/csrf.rst @@ -108,6 +108,15 @@ this can be customized on a form-by-form basis:: // ... } +You can also customize the rendering of the CSRF form field creating a custom +:doc:`form theme ` and using ``csrf_token`` as the prefix of +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/service_container/alias_private.rst b/service_container/alias_private.rst index 756ab691b68..eda3658c778 100644 --- a/service_container/alias_private.rst +++ b/service_container/alias_private.rst @@ -146,6 +146,69 @@ This means that when using the container directly, you can access the # ... app.mailer: '@App\Mail\PhpMailer' +Deprecating Service Aliases +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you decide to deprecate the use of a service alias (because it is outdated +or you decided not to maintain it anymore), you can deprecate its definition: + +.. configuration-block:: + + .. code-block:: yaml + + app.mailer: + alias: '@AppBundle\Mail\PhpMailer' + + # this will display a generic deprecation message... + deprecated: true + + # ...but you can also define a custom deprecation message + deprecated: 'The "%alias_id%" alias is deprecated. Don\'t use it anymore.' + + .. code-block:: xml + + + + + + + + + + + The "%alias_id%" service alias is deprecated. Don't use it anymore. + + + + + .. code-block:: php + + $container + ->setAlias('app.mailer', 'App\Mail\PhpMailer') + + // this will display a generic deprecation message... + ->setDeprecated(true) + + // ...but you can also define a custom deprecation message + ->setDeprecated( + true, + 'The "%alias_id%" service alias is deprecated. Don\'t use it anymore.' + ) + ; + +Now, every time this service alias is used, a deprecation warning is triggered, +advising you to stop or to change your uses of that alias. + +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 ------------------ From 218f5d23cbf7163a60edda1ea9503737406fcbe6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 7 Mar 2019 10:56:14 +0100 Subject: [PATCH 031/499] Updated the versionadded directive --- reference/constraints/CardScheme.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/CardScheme.rst b/reference/constraints/CardScheme.rst index 1f0ae7a7ebf..706448ebf46 100644 --- a/reference/constraints/CardScheme.rst +++ b/reference/constraints/CardScheme.rst @@ -125,7 +125,7 @@ Valid values are: .. versionadded:: 4.3 - The ``UATP`` number scheme was introduced in Symfony 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)`_. From 8fc1b5363d37c388ebb324e50d4f124fd5e17eab Mon Sep 17 00:00:00 2001 From: fancyweb Date: Mon, 14 Jan 2019 22:31:45 +0100 Subject: [PATCH 032/499] [Form] Add input_format option to DateType, DateTimeType and TimeType --- reference/forms/types/birthday.rst | 3 +++ reference/forms/types/date.rst | 3 +++ reference/forms/types/datetime.rst | 8 ++++++++ .../forms/types/options/date_input_format.rst.inc | 6 ++++++ .../options/date_input_format_description.rst.inc | 8 ++++++++ reference/forms/types/time.rst | 15 +++++++++++++++ 6 files changed, 43 insertions(+) create mode 100644 reference/forms/types/options/date_input_format.rst.inc create mode 100644 reference/forms/types/options/date_input_format_description.rst.inc diff --git a/reference/forms/types/birthday.rst b/reference/forms/types/birthday.rst index cb4281fb370..257e13dcc42 100644 --- a/reference/forms/types/birthday.rst +++ b/reference/forms/types/birthday.rst @@ -29,6 +29,7 @@ option defaults to 120 years ago to the current year. | | - `placeholder`_ | | | - `format`_ | | | - `input`_ | +| | - `input_format`_ | | | - `model_timezone`_ | | | - `months`_ | | | - `view_timezone`_ | @@ -96,6 +97,8 @@ values for the year, month and day fields:: .. include:: /reference/forms/types/options/date_input.rst.inc +.. include:: /reference/forms/types/options/date_input_format.rst.inc + .. include:: /reference/forms/types/options/model_timezone.rst.inc .. include:: /reference/forms/types/options/months.rst.inc diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index 16dcae7c1fe..2ecbbc4961b 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -21,6 +21,7 @@ and can understand a number of different input formats via the `input`_ option. | | - `format`_ | | | - `html5`_ | | | - `input`_ | +| | - `input_format`_ | | | - `model_timezone`_ | | | - `months`_ | | | - `view_timezone`_ | @@ -168,6 +169,8 @@ values for the year, month and day fields:: .. include:: /reference/forms/types/options/date_input.rst.inc +.. include:: /reference/forms/types/options/date_input_format.rst.inc + .. include:: /reference/forms/types/options/model_timezone.rst.inc .. include:: /reference/forms/types/options/months.rst.inc diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index a50b2ce7061..efb5a80435b 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -25,6 +25,7 @@ the data can be a ``DateTime`` object, a string, a timestamp or an array. | | - `hours`_ | | | - `html5`_ | | | - `input`_ | +| | - `input_format`_ | | | - `minutes`_ | | | - `model_timezone`_ | | | - `months`_ | @@ -153,6 +154,13 @@ this format. .. include:: /reference/forms/types/options/_date_limitation.rst.inc +input_format +~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``Y-m-d H:i:s`` + +.. include:: /reference/forms/types/options/date_input_format_description.rst.inc + .. include:: /reference/forms/types/options/minutes.rst.inc .. include:: /reference/forms/types/options/model_timezone.rst.inc diff --git a/reference/forms/types/options/date_input_format.rst.inc b/reference/forms/types/options/date_input_format.rst.inc new file mode 100644 index 00000000000..ead92072642 --- /dev/null +++ b/reference/forms/types/options/date_input_format.rst.inc @@ -0,0 +1,6 @@ +input_format +~~~~~~~~~~~~ + +**type**: ``string`` **default**: ``Y-m-d`` + +.. include:: /reference/forms/types/options/date_input_format_description.rst.inc diff --git a/reference/forms/types/options/date_input_format_description.rst.inc b/reference/forms/types/options/date_input_format_description.rst.inc new file mode 100644 index 00000000000..4cd9b353e31 --- /dev/null +++ b/reference/forms/types/options/date_input_format_description.rst.inc @@ -0,0 +1,8 @@ +.. 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`_. + +.. _`PHP date format`: https://secure.php.net/manual/en/function.date.php diff --git a/reference/forms/types/time.rst b/reference/forms/types/time.rst index 9c39dabccff..9c9c09865d0 100644 --- a/reference/forms/types/time.rst +++ b/reference/forms/types/time.rst @@ -20,6 +20,7 @@ stored as a ``DateTime`` object, a string, a timestamp or an array. | | - `hours`_ | | | - `html5`_ | | | - `input`_ | +| | - `input_format`_ | | | - `minutes`_ | | | - `model_timezone`_ | | | - `seconds`_ | @@ -129,6 +130,18 @@ on your underlying object. Valid values are: The value that comes back from the form will also be normalized back into this format. +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`_. + .. include:: /reference/forms/types/options/minutes.rst.inc .. include:: /reference/forms/types/options/model_timezone.rst.inc @@ -222,3 +235,5 @@ Form Variables | type | ``string`` | Only present when widget is ``single_text`` and HTML5 is activated, | | | | contains the input type to use (``datetime``, ``date`` or ``time``). | +--------------+-------------+----------------------------------------------------------------------+ + +.. _`PHP time format`: https://secure.php.net/manual/en/function.date.php From a2e6c2ac93d442cf277d686f34bb0f5004560805 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Thu, 7 Mar 2019 15:14:37 -0500 Subject: [PATCH 033/499] Documenting the new method addNormalizer in OptionsResolver component --- components/options_resolver.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 4b2526872d6..ca3b1baf6e1 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -437,6 +437,14 @@ if you need to use other options during normalization:: } } +.. versionadded:: 4.3 + + To normalize a new allowed value in sub-classes that is being normalized + in parent classes use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::addNormalizer`. + This way, the ``$value`` argument will receive the previously normalized + value, otherwise you can prepend the new normalizer by passing ``true`` as + third argument. + Default Values that Depend on another Option ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 48b0cec9f4106f355cdd4274ff4558053f74f183 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 8 Mar 2019 11:01:40 +0100 Subject: [PATCH 034/499] add missing versionadded directives for Bic options --- reference/constraints/Bic.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/reference/constraints/Bic.rst b/reference/constraints/Bic.rst index 49060cf5f64..569f1f977ee 100644 --- a/reference/constraints/Bic.rst +++ b/reference/constraints/Bic.rst @@ -94,6 +94,10 @@ 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 @@ -101,6 +105,10 @@ 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 @@ -108,6 +116,10 @@ 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 From 06a71a9a33174ec5fd840b811f87263dab8bc213 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sun, 10 Mar 2019 19:33:48 +0100 Subject: [PATCH 035/499] [Routing][DX] Exposed "compiler_class" and "utf8" options --- components/routing.rst | 82 +++++++++++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/components/routing.rst b/components/routing.rst index a46922505ea..9c9c454cd3b 100644 --- a/components/routing.rst +++ b/components/routing.rst @@ -399,7 +399,7 @@ routes with UTF-8 characters: class DefaultController extends AbstractController { /** - * @Route("/category/{name}", name="route1", options={"utf8": true}) + * @Route("/category/{name}", name="route1", utf8=true) */ public function category() { @@ -411,8 +411,7 @@ routes with UTF-8 characters: route1: path: /category/{name} controller: App\Controller\DefaultController::category - options: - utf8: true + utf8: true .. code-block:: xml @@ -422,9 +421,10 @@ routes with UTF-8 characters: xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - - - + .. code-block:: php @@ -437,12 +437,61 @@ routes with UTF-8 characters: return function (RoutingConfigurator $routes) { $routes->add('route1', '/category/{name}') ->controller([DefaultController::class, 'category']) - ->options([ - 'utf8' => true, - ]) + ->utf8() ; }; +.. versionadded:: 4.3 + + The ``utf8`` shortcut has been introduced in Symfony 4.3. + Before you has 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: @@ -467,7 +516,7 @@ You can also include UTF-8 strings as routing requirements: * "/category/{name}", * name="route2", * defaults={"name"="한국어"}, - * options={"utf8": true} + * utf8=true * ) */ public function category() @@ -482,8 +531,7 @@ You can also include UTF-8 strings as routing requirements: controller: 'App\Controller\DefaultController::category' defaults: name: "한국어" - options: - utf8: true + utf8: true .. code-block:: xml @@ -493,9 +541,11 @@ You can also include UTF-8 strings as routing requirements: xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - + 한국어 - @@ -512,9 +562,7 @@ You can also include UTF-8 strings as routing requirements: ->defaults([ 'name' => '한국어', ]) - ->options([ - 'utf8' => true, - ]) + ->utf8() ; }; From 309bd58bca188dd0c04796036d94ef35cb3fab58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 10 Mar 2019 20:37:17 +0100 Subject: [PATCH 036/499] Document Default env processor with null fallback --- configuration/external_parameters.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index 5f2cdd3a83b..67598af81c9 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -533,6 +533,8 @@ Symfony provides the following env var processors: $container->setParameter('private_key', '%env(default:raw_key:file:PRIVATE_KEY)%'); $container->setParameter('raw_key', '%env(PRIVATE_KEY)%'); + When the fallback parameter is ommited (ie. ``env(default::API_KEY)``), the value retrieved is ``null``. + .. versionadded:: 4.3 The ``default`` processor was introduced in Symfony 4.3. From 7c081f11c70f5d43188f3354aa5eaab9394cdf17 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 11 Mar 2019 09:43:27 +0100 Subject: [PATCH 037/499] Fixed more XSD URLs --- configuration/external_parameters.rst | 4 ++-- configuration/override_dir_structure.rst | 2 +- reference/configuration/framework.rst | 2 +- reference/constraints/Json.rst | 2 +- service_container/alias_private.rst | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index 3516466ca02..81fdca3aa68 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -515,9 +515,9 @@ Symfony provides the following env var processors: 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 - http://symfony.com/schema/dic/services/services-1.0.xsd + https://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/symfony - http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> %env(default:raw_key:file:PRIVATE_KEY)% diff --git a/configuration/override_dir_structure.rst b/configuration/override_dir_structure.rst index 4e9b2719335..0d312de3826 100644 --- a/configuration/override_dir_structure.rst +++ b/configuration/override_dir_structure.rst @@ -154,7 +154,7 @@ configuration option to define your own translations directory (or directories): xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:twig="http://symfony.com/schema/dic/twig" xsi:schemaLocation="http://symfony.com/schema/dic/services - http://symfony.com/schema/dic/services/services-1.0.xsd + https://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/twig https://symfony.com/schema/dic/twig/twig-1.0.xsd"> diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index b4593011e29..ccb6a344ef5 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -311,7 +311,7 @@ doubling them to prevent Symfony from interpreting them as container parameters) 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 - https://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + https://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> diff --git a/reference/constraints/Json.rst b/reference/constraints/Json.rst index c993881003e..085fbe718c9 100644 --- a/reference/constraints/Json.rst +++ b/reference/constraints/Json.rst @@ -53,7 +53,7 @@ The ``Json`` constraint can be applied to a property or a "getter" method: + xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst index 2c2751fc86e..a15a6229083 100644 --- a/service_container/alias_private.rst +++ b/service_container/alias_private.rst @@ -170,7 +170,7 @@ or you decided not to maintain it anymore), you can deprecate its definition: + xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> From 5395ea4b207c36ed3c2762f41815e4cf32d1c967 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 11 Mar 2019 10:05:52 +0100 Subject: [PATCH 038/499] Minor tweak --- configuration/external_parameters.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index a1b8ce5a4ae..51abfb313c2 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -533,7 +533,8 @@ Symfony provides the following env var processors: $container->setParameter('private_key', '%env(default:raw_key:file:PRIVATE_KEY)%'); $container->setParameter('raw_key', '%env(PRIVATE_KEY)%'); - When the fallback parameter is ommited (ie. ``env(default::API_KEY)``), the value retrieved is ``null``. + When the fallback parameter is ommited (e.g. ``env(default::API_KEY)``), the + value returned is ``null``. .. versionadded:: 4.3 From f034d994fc3296ad983e1ac46cf3c683e3972a3a Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 11 Mar 2019 10:34:36 +0100 Subject: [PATCH 039/499] [#11127] fix minor typo --- configuration/external_parameters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index 51abfb313c2..bc940d91db6 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -533,7 +533,7 @@ Symfony provides the following env var processors: $container->setParameter('private_key', '%env(default:raw_key:file:PRIVATE_KEY)%'); $container->setParameter('raw_key', '%env(PRIVATE_KEY)%'); - When the fallback parameter is ommited (e.g. ``env(default::API_KEY)``), the + When the fallback parameter is omitted (e.g. ``env(default::API_KEY)``), the value returned is ``null``. .. versionadded:: 4.3 From a94b9201c006568be33fb2375d86c9ef4c65ff7f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 13 Mar 2019 11:12:46 +0100 Subject: [PATCH 040/499] Document the disallow_search_engine_index option --- reference/configuration/framework.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index ccb6a344ef5..a01018268ae 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -73,6 +73,7 @@ Configuration * :ref:`enabled ` * `default_locale`_ +* `disallow_search_engine_index`_ * `esi`_ * :ref:`enabled ` @@ -384,6 +385,21 @@ method. You can read more information about the default locale in :ref:`translation-default-locale`. +disallow_search_engine_index +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**type**: ``boolean`` **default**: ``true`` when the debug mode is enabled, ``false`` otherwise. + +.. versionadded:: 4.3 + + The ``disallow_search_engine_index`` option was introduced in Symfony 4.3. + +If ``true``, Symfony adds a ``X-Robots-Tag: noindex`` HTTP tag to all responses +(unless your own app adds that header, in which case it's not modified). This +`X-Robots-Tag HTTP header`_ tells search engines to not index your web site. +This option is a protection measure in case you accidentally publish your site +in debug mode. + trusted_hosts ~~~~~~~~~~~~~ @@ -2340,3 +2356,4 @@ a :doc:`normal workflow ` or a :doc:`state machine Date: Fri, 15 Mar 2019 11:31:21 +0100 Subject: [PATCH 041/499] Minor reword --- routing/service_container_parameters.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/routing/service_container_parameters.rst b/routing/service_container_parameters.rst index 691256cf0ad..7b33900ec7a 100644 --- a/routing/service_container_parameters.rst +++ b/routing/service_container_parameters.rst @@ -55,6 +55,10 @@ 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: @@ -138,7 +142,3 @@ path): For parameter handling within a Dependency Injection Class see :doc:`/configuration/using_parameters_in_dic`. - -.. versionadded:: 4.3 - - Support for boolean container parameters was introduced in Symfony 4.3. From d53e11e3b29255ce379d9a50bf92d83b87e5c436 Mon Sep 17 00:00:00 2001 From: Kim Wuestkamp Date: Thu, 14 Mar 2019 12:38:43 +0100 Subject: [PATCH 042/499] updated PropertyAccess docs for PR 30536 --- components/property_access.rst | 24 ++++++++++++++++++++++++ reference/configuration/framework.rst | 13 +++++++++++++ 2 files changed, 37 insertions(+) diff --git a/components/property_access.rst b/components/property_access.rst index 2e23043e562..c05f6cbfcc1 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -168,6 +168,30 @@ getters, this means that you can do something like this:: This will produce: ``He is an author`` +Accessing a non existing property path +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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 behaviour using the :method:`Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder::disableExceptionOnInvalidPropertyPath` +method:: + + // ... + $propertyAccessor = PropertyAccess::createPropertyAccessorBuilder() + ->disableExceptionOnInvalidPropertyPath() + ->getPropertyAccessor(); + + class Person + { + public $name; + } + + $person = new Person(); + + // instead of throwing an exception the following code returns null + $value = $propertyAccessor->getValue($person, 'birthday'); + + Magic ``__get()`` Method ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index a01018268ae..bef9ff8ed9a 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -107,6 +107,7 @@ Configuration * `magic_call`_ * `throw_exception_on_invalid_index`_ + * `throw_exception_on_invalid_property_path`_ * `property_info`_ @@ -1726,6 +1727,18 @@ throw_exception_on_invalid_index When enabled, the ``property_accessor`` service throws an exception when you try to access an invalid index of an array. +throw_exception_on_invalid_property_path +........................................ + +**type**: ``boolean`` **default**: ``true`` + +.. versionadded:: 4.3 + + The ``throw_exception_on_invalid_property_path`` option was introduced in Symfony 4.3. + +When enabled, the ``property_accessor`` service throws an exception when you +try to access an invalid property path of an object. + property_info ~~~~~~~~~~~~~ From 4fb0d0af385c8a96a792bf02867c34838bde7f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 10 Mar 2019 21:29:39 +0100 Subject: [PATCH 043/499] Add `url` and `query_string` processors --- configuration/external_parameters.rst | 122 ++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index 5f2cdd3a83b..23b506a62e3 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -537,6 +537,128 @@ Symfony provides the following env var processors: The ``default`` processor was introduced in Symfony 4.3. +``env(url:FOO)`` + Parses an absolute URL and returns its components. + + .. code-block:: bash + + # .env + MONGODB_URL="mongodb://db_user:db_password@127.0.0.1:27017/db_name" + + .. configuration-block:: + + .. code-block:: yaml + + # config/packages/mongodb.yaml + mongo_db_bundle: + clients: + default: + hosts: + - { host: '%env(key:host:url:MONGODB_URL)%', port: '%env(key:port:url:MONGODB_URL)%' } + username: '%env(key:user:url:MONGODB_URL)%' + password: '%env(key:pass:url:MONGODB_URL)%' + connections: + default: + database_name: '%env(key:path:url:MONGODB_URL)%' + + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/mongodb.php + $container->loadFromExtension('mongodb', [ + 'clients' => [ + 'default' => [ + 'hosts' => [ + [ + 'host' => '%env(key:host:url:MONGODB_URL)%', + 'port' => '%env(key:port:url:MONGODB_URL)%', + ], + ], + 'username' => '%env(key:user:url:MONGODB_URL)%', + 'password' => '%env(key:pass:url:MONGODB_URL)%', + ], + ], + 'connections' => [ + 'default' => [ + 'database_name' => '%env(key:path:url:MONGODB_URL)%', + ], + ], + ]); + + .. caution:: + + In order to ease extraction of the resource from the URL, The leading + ``/`` is trimed from the ``path`` component. + + .. versionadded:: 4.3 + + The ``url`` processor was introduced in Symfony 4.3. + +``env(query_string:FOO)`` + Parses an encoded string as if it were the query string passed via a URL. + + .. code-block:: bash + + # .env + MONGODB_URL="mongodb://db_user:db_password@127.0.0.1:27017/db_name?timeout=3000" + + .. configuration-block:: + + .. code-block:: yaml + + # config/packages/mongodb.yaml + mongo_db_bundle: + clients: + default: + # ... + connectTimeoutMS: '%env(int:key:timeout:query_string:MONGODB_URL)%' + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/packages/mongodb.php + $container->loadFromExtension('mongodb', [ + 'clients' => [ + 'default' => [ + // ... + 'connectTimeoutMS' => '%env(int:key:timeout:query_string:MONGODB_URL)%', + ], + ], + ]); + + .. 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 From f1eae4496e588674384d6e3ca98df390ec69e778 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sun, 17 Mar 2019 18:33:56 +0100 Subject: [PATCH 044/499] added doc for defaults --- routing.rst | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/routing.rst b/routing.rst index 10e708d829e..553f29b5487 100644 --- a/routing.rst +++ b/routing.rst @@ -623,7 +623,10 @@ With all of this in mind, check out this advanced example: /** * @Route( * "/articles/{_locale}/{year}/{slug}.{_format}", - * defaults={"_format": "html"}, + * defaults={ + * "_locale": "en", + * "_format": "html" + * }, * requirements={ * "_locale": "en|fr", * "_format": "html|rss", @@ -643,6 +646,7 @@ With all of this in mind, check out this advanced example: path: /articles/{_locale}/{year}/{slug}.{_format} controller: App\Controller\ArticleController::show defaults: + _locale: en _format: html requirements: _locale: en|fr @@ -662,6 +666,7 @@ With all of this in mind, check out this advanced example: path="/articles/{_locale}/{year}/{slug}.{_format}" controller="App\Controller\ArticleController::show"> + en html en|fr html|rss @@ -681,6 +686,7 @@ With all of this in mind, check out this advanced example: $routes->add('article_show', '/articles/{_locale}/{year}/{slug}.{_format}') ->controller([ArticleController::class, 'show']) ->defaults([ + '_locale' => 'en', '_format' => 'html', ]) ->requirements([ @@ -739,6 +745,92 @@ that are special: each adds a unique piece of functionality inside your applicat ``_locale`` Used to set the locale on the request (:ref:`read more `). +You can also use special attributes to configure them: + +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Controller/ArticleController.php + + // ... + class ArticleController extends AbstractController + { + /** + * @Route( + * "/articles/{_locale}/search.{_format}", + * locale="en", + * format="html", + * fragment="first-result-id", + * requirements={ + * "_locale": "en|fr", + * "_format": "html|xml", + * } + * ) + */ + public function search() + { + } + } + + .. code-block:: yaml + + # config/routes.yaml + article_search: + path: /articles/{_locale}/search.{_format} + controller: App\Controller\ArticleController::search + locale: en + format: html + requirements: + _locale: en|fr + _format: html|xml + + .. code-block:: xml + + + + + + + + en|fr + html|rss + \d+ + + + + + .. code-block:: php + + // config/routes.php + namespace Symfony\Component\Routing\Loader\Configurator; + + use App\Controller\ArticleController; + + return function (RoutingConfigurator $routes) { + $routes->add('article_show', '/articles/{_locale}/search.{_format}') + ->controller([ArticleController::class, 'search']) + ->locale('en') + ->format('html) + ->requirements([ + '_locale' => 'en|fr', + '_format' => 'html|rss', + 'year' => '\d+', + ]) + ; + }; + +.. versionadded:: + + The special attributes has been introduced in Symfony 4.3. + .. _routing-trailing-slash-redirection: Redirecting URLs with Trailing Slashes From f9e2eaa1d1de665e452d417728fcd3d85787e4d4 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sun, 17 Mar 2019 19:08:49 +0100 Subject: [PATCH 045/499] fixup --- routing.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/routing.rst b/routing.rst index 553f29b5487..357fc5f36a6 100644 --- a/routing.rst +++ b/routing.rst @@ -745,7 +745,7 @@ that are special: each adds a unique piece of functionality inside your applicat ``_locale`` Used to set the locale on the request (:ref:`read more `). -You can also use special attributes to configure them: +You can also use special attributes to configure them (except ``_fragment``): .. configuration-block:: @@ -761,7 +761,6 @@ You can also use special attributes to configure them: * "/articles/{_locale}/search.{_format}", * locale="en", * format="html", - * fragment="first-result-id", * requirements={ * "_locale": "en|fr", * "_format": "html|xml", @@ -802,7 +801,6 @@ You can also use special attributes to configure them: en|fr html|rss - \d+ @@ -822,11 +820,12 @@ You can also use special attributes to configure them: ->requirements([ '_locale' => 'en|fr', '_format' => 'html|rss', - 'year' => '\d+', ]) ; }; +Those attributes can also be used for imports. + .. versionadded:: The special attributes has been introduced in Symfony 4.3. From 16b2e4b3615ce645091e9cd5edf52ca6f3bdafa3 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 4 Mar 2019 10:31:06 +0100 Subject: [PATCH 046/499] Docs for PercentType disable/customize percent character --- reference/forms/types/percent.rst | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index 3485fb52766..b90c33e6f0a 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -9,12 +9,14 @@ percentage data. If your percentage data is stored as a decimal (e.g. ``0.95``), you can use this field out-of-the-box. If you store your data as a number (e.g. ``95``), you should set the ``type`` option to ``integer``. -This field adds a percentage sign "``%``" after the input box. +When ``symbol`` is true, the field will add a percentage sign "``%``" after the +input. +-------------+-----------------------------------------------------------------------+ | Rendered as | ``input`` ``text`` field | +-------------+-----------------------------------------------------------------------+ | Options | - `scale`_ | +| | - `symbol`_ | | | - `type`_ | +-------------+-----------------------------------------------------------------------+ | Overridden | - `compound`_ | @@ -54,6 +56,20 @@ scale By default, the input numbers are rounded. To allow for more decimal places, use this option. +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 the string value instead +of the default ``%`` sign. + type ~~~~ From d24bb04bc05dbf9fe35b40465cb144784caad1a6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 25 Mar 2019 16:42:25 +0100 Subject: [PATCH 047/499] Minor tweaks --- configuration/external_parameters.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index 1f2f0a480a1..e5e12eab320 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -541,7 +541,7 @@ Symfony provides the following env var processors: The ``default`` processor was introduced in Symfony 4.3. ``env(url:FOO)`` - Parses an absolute URL and returns its components. + Parses an absolute URL and returns its components as an associative array. .. code-block:: bash @@ -557,7 +557,7 @@ Symfony provides the following env var processors: clients: default: hosts: - - { host: '%env(key:host:url:MONGODB_URL)%', port: '%env(key:port:url:MONGODB_URL)%' } + - { host: '%env(key:host:url:MONGODB_URL)%', port: '%env(key:port:url:MONGODB_URL)%' } username: '%env(key:user:url:MONGODB_URL)%' password: '%env(key:pass:url:MONGODB_URL)%' connections: @@ -606,15 +606,16 @@ Symfony provides the following env var processors: .. caution:: - In order to ease extraction of the resource from the URL, The leading - ``/`` is trimed from the ``path`` component. + 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 an encoded string as if it were the query string passed via a URL. + Parses the query string part of the given URL and returns its components as + an associative array. .. code-block:: bash From 5dc1c9f8d46c56b0611cbb3b0c78c3adca94a6b2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 25 Mar 2019 17:16:45 +0100 Subject: [PATCH 048/499] Minor tweaks --- components/routing.rst | 25 ++++++++++++------------- routing.rst | 18 +++++++++--------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/components/routing.rst b/components/routing.rst index 911aefcf9b6..cbf36763a45 100644 --- a/components/routing.rst +++ b/components/routing.rst @@ -424,7 +424,7 @@ routes with UTF-8 characters: + utf8="true"/> .. code-block:: php @@ -443,25 +443,24 @@ routes with UTF-8 characters: .. versionadded:: 4.3 - The ``utf8`` shortcut has been introduced in Symfony 4.3. - Before you has to use the ``options`` setting to define - this value: + 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} + path: /category/{name} controller: App\Controller\DefaultController::category - options: { utf8: true } + options: { utf8: true } - .. code-block:: yaml + .. code-block:: yaml - route1: - path: /category/{name} - controller: App\Controller\DefaultController::category - utf8: true + route1: + path: /category/{name} + controller: App\Controller\DefaultController::category + utf8: true .. code-block:: xml @@ -473,7 +472,7 @@ routes with UTF-8 characters: + controller="App\Controller\DefaultController::category"> @@ -544,7 +543,7 @@ You can also include UTF-8 strings as routing requirements: + utf8="true"> 한국어 diff --git a/routing.rst b/routing.rst index 6a81974cb86..5f27bd58bdc 100644 --- a/routing.rst +++ b/routing.rst @@ -776,13 +776,13 @@ You can also use special attributes to configure them (except ``_fragment``): # config/routes.yaml article_search: - path: /articles/{_locale}/search.{_format} - controller: App\Controller\ArticleController::search - locale: en - format: html + path: /articles/{_locale}/search.{_format} + controller: App\Controller\ArticleController::search + locale: en + format: html requirements: - _locale: en|fr - _format: html|xml + _locale: en|fr + _format: html|xml .. code-block:: xml @@ -816,7 +816,7 @@ You can also use special attributes to configure them (except ``_fragment``): $routes->add('article_show', '/articles/{_locale}/search.{_format}') ->controller([ArticleController::class, 'search']) ->locale('en') - ->format('html) + ->format('html') ->requirements([ '_locale' => 'en|fr', '_format' => 'html|rss', @@ -824,11 +824,11 @@ You can also use special attributes to configure them (except ``_fragment``): ; }; -Those attributes can also be used for imports. +These attributes can also be used for route imports. .. versionadded:: - The special attributes has been introduced in Symfony 4.3. + The special attributes were introduced in Symfony 4.3. .. _routing-trailing-slash-redirection: From 6d7ec3f58fe409aa0af91cd15a12508ebe9267ce Mon Sep 17 00:00:00 2001 From: Ahmed Abdou Date: Mon, 25 Mar 2019 23:48:09 +0100 Subject: [PATCH 049/499] adding ignoreVCSIgnored documentation --- components/finder.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/finder.rst b/components/finder.rst index 25cefdb2370..53da99bca7e 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -355,6 +355,15 @@ Restrict by a depth range by chaining calls or passing an array:: // same as above $finder->depth(['> 2', '< 5']); +Gitignore +~~~~~~~~~~~~~~~ + +The Finder can follow .gitignore file rules. :method:`Symfony\\Component\\Finder\\Finder::ignoreVCSIgnored`:: + + $finder->ignoreVCSIgnored(true); + +This will exclude files based on .gitignore rules as git does. + Custom Filtering ~~~~~~~~~~~~~~~~ From 25e83499dc716c4a0b246feb1fd76c7d7c3eb357 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 26 Mar 2019 08:45:39 +0100 Subject: [PATCH 050/499] Fixed a RST syntax issue --- routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing.rst b/routing.rst index 5f27bd58bdc..ab954a345aa 100644 --- a/routing.rst +++ b/routing.rst @@ -826,7 +826,7 @@ You can also use special attributes to configure them (except ``_fragment``): These attributes can also be used for route imports. -.. versionadded:: +.. versionadded:: 4.3 The special attributes were introduced in Symfony 4.3. From 3cd90b350a07647621064b902e08123cc73cf082 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 26 Mar 2019 08:56:07 +0100 Subject: [PATCH 051/499] Minor tweaks --- components/finder.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/finder.rst b/components/finder.rst index 53da99bca7e..e7b89bfb500 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -356,13 +356,17 @@ Restrict by a depth range by chaining calls or passing an array:: $finder->depth(['> 2', '< 5']); Gitignore -~~~~~~~~~~~~~~~ +~~~~~~~~~ -The Finder can follow .gitignore file rules. :method:`Symfony\\Component\\Finder\\Finder::ignoreVCSIgnored`:: +The Finder can follow ``.gitignore`` file rules with the :method:`Symfony\\Component\\Finder\\Finder::ignoreVCSIgnored` method:: $finder->ignoreVCSIgnored(true); -This will exclude files based on .gitignore rules as git does. +This will exclude files based on ``.gitignore`` rules as git does. + +.. versionadded:: 4.3 + + The ``ignoreVCSIgnored()`` method was introduced in Symfony 4.3. Custom Filtering ~~~~~~~~~~~~~~~~ From 92cae4b0310616d62c7e8472b8d87bd2957316d3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 27 Mar 2019 10:29:32 +0100 Subject: [PATCH 052/499] Reordered a section of the Finder component --- components/finder.rst | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/components/finder.rst b/components/finder.rst index 8ebe354b0bb..d74f771b576 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -145,6 +145,17 @@ default when looking for files and directories, but you can change this with the $finder->ignoreVCS(false); +If your project defines a ``.gitignore`` file, you can reuse those rules to +exclude files and directories from the results with the +:method:`Symfony\\Component\\Finder\\Finder::ignoreVCSIgnored` method:: + + // excludes files/directories matching the .gitignore patterns + $finder->ignoreVCSIgnored(true); + +.. versionadded:: 4.3 + + The ``ignoreVCSIgnored()`` method was introduced in Symfony 4.3. + File Name ~~~~~~~~~ @@ -305,19 +316,6 @@ Restrict by a depth range by chaining calls or passing an array:: // same as above $finder->depth(['> 2', '< 5']); -Gitignore -~~~~~~~~~ - -The Finder can follow ``.gitignore`` file rules with the :method:`Symfony\\Component\\Finder\\Finder::ignoreVCSIgnored` method:: - - $finder->ignoreVCSIgnored(true); - -This will exclude files based on ``.gitignore`` rules as git does. - -.. versionadded:: 4.3 - - The ``ignoreVCSIgnored()`` method was introduced in Symfony 4.3. - Custom Filtering ~~~~~~~~~~~~~~~~ From 7fae953a82f094cd26446abb9959be7e4dfd4355 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 27 Mar 2019 12:25:58 +0100 Subject: [PATCH 053/499] Minor tweak --- components/finder.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/finder.rst b/components/finder.rst index d74f771b576..0ef1e482a6d 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -145,8 +145,8 @@ default when looking for files and directories, but you can change this with the $finder->ignoreVCS(false); -If your project defines a ``.gitignore`` file, you can reuse those rules to -exclude files and directories from the results with the +If the search directory contains a ``.gitignore`` file, you can reuse those +rules to exclude files and directories from the results with the :method:`Symfony\\Component\\Finder\\Finder::ignoreVCSIgnored` method:: // excludes files/directories matching the .gitignore patterns From 3e35008f2761af158056f16341932e8db13fd95d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 27 Mar 2019 17:40:06 +0100 Subject: [PATCH 054/499] Minor tweaks --- reference/forms/types/percent.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/reference/forms/types/percent.rst b/reference/forms/types/percent.rst index b90c33e6f0a..b90d57de2b5 100644 --- a/reference/forms/types/percent.rst +++ b/reference/forms/types/percent.rst @@ -9,8 +9,8 @@ percentage data. If your percentage data is stored as a decimal (e.g. ``0.95``), you can use this field out-of-the-box. If you store your data as a number (e.g. ``95``), you should set the ``type`` option to ``integer``. -When ``symbol`` is true, the field will add a percentage sign "``%``" after the -input. +When ``symbol`` is ``true``, the field will add a percentage sign "``%``" after +the input. +-------------+-----------------------------------------------------------------------+ | Rendered as | ``input`` ``text`` field | @@ -66,9 +66,9 @@ symbol 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 the string value instead -of the default ``%`` sign. +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 +``%`` sign. type ~~~~ From 2a29904c0700e2ef602f0636a57d9249139874d1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 27 Mar 2019 17:49:36 +0100 Subject: [PATCH 055/499] Minor tweak for the debug:router output --- routing/debug.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/routing/debug.rst b/routing/debug.rst index 861de0bdd0a..f83331488cc 100644 --- a/routing/debug.rst +++ b/routing/debug.rst @@ -63,4 +63,9 @@ which route is associated with the given URL: | Defaults | _controller: App\Controller\BlogController:show | | Options | compiler_class: Symfony\Component\Routing\RouteCompiler | | | 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. From a237e2451f3976a130822c503f074cb35d451fe5 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 27 Mar 2019 19:33:31 +0100 Subject: [PATCH 056/499] clarify datetime type option deprecations --- reference/forms/types/datetime.rst | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/reference/forms/types/datetime.rst b/reference/forms/types/datetime.rst index 31780d73084..99fb9aa1722 100644 --- a/reference/forms/types/datetime.rst +++ b/reference/forms/types/datetime.rst @@ -74,8 +74,10 @@ Defines the ``format`` option that will be passed down to the date field. See the :ref:`DateType's format option ` for more details. -The ``date_format`` option does not have any effect when the form is rendered -as an HTML5 datetime input. +.. 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 ~~~~~~~~~~ @@ -96,7 +98,10 @@ date_widget .. include:: /reference/forms/types/options/date_widget_description.rst.inc -The ``date_widget`` option is ignored when the ``widget`` option is set to ``single_text``. +.. 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 @@ -139,7 +144,7 @@ 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`_. -.. versionadded:: 4.3 +.. deprecated:: 4.3 Using the ``format`` option when the ``html5`` option is enabled is deprecated since Symfony 4.3. @@ -203,7 +208,10 @@ time_widget Defines the ``widget`` option for the :doc:`TimeType `. -The ``time_widget`` option is ignored when the ``widget`` option is set to ``single_text``. +.. 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 @@ -216,11 +224,6 @@ Defines the ``widget`` option for both the :doc:`DateType `. This can be overridden with the `date_widget`_ and `time_widget`_ options. -.. versionadded:: 4.3 - - Using the ``date_format``, ``date_widget``, and ``time_widget`` options when - the ``widget`` option is set to ``single_text`` is deprecated since Symfony 4.3. - .. include:: /reference/forms/types/options/with_minutes.rst.inc .. include:: /reference/forms/types/options/with_seconds.rst.inc From a641baaf2192fb698f59890f76d61a6d40354f52 Mon Sep 17 00:00:00 2001 From: Joe Bennett Date: Thu, 28 Mar 2019 19:41:05 +1000 Subject: [PATCH 057/499] #27345 Added docs for Symfony\Component\Lock\Store\MongoDbStore --- components/lock.rst | 88 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index a72cd68ec84..66748fa5707 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -169,6 +169,7 @@ 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 @@ -215,6 +216,38 @@ support blocking, and expects a TTL to avoid stalled locks:: Memcached does not support TTL lower than 1 second. +.. _lock-store-mongodb: + +MongoDbStore +~~~~~~~~~~~~ + +.. versionadded:: 4.3 + The MongoDbStore was introduced 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:: + + use Symfony\Component\Lock\Store\MongoDbStore; + + $mongoClient = new \MongoDB\Client('mongo://localhost/'); + + $options = array( + 'database' => 'my-app', + ); + + $store = new MongoDbStore($mongoClient, $options); + +The ``MongoDbStore`` takes the following ``$options``: + +============ ========= ======================================================================== +Option Default Description +============ ========= ======================================================================== +database The name of the database [Mandatory] +collection ``lock`` The name of the collection +gcProbablity ``0.001`` Should a TTL Index be created expressed as a probability from 0.0 to 1.0 +============ ========= ======================================================================== + .. _lock-store-pdo: PdoStore @@ -351,7 +384,8 @@ Remote Stores ~~~~~~~~~~~~~ Remote stores (:ref:`MemcachedStore `, -:ref:`PdoStore `, :ref:`RedisStore `, and +:ref:`MongoDbStore `, :ref:`PdoStore `, +:ref:`RedisStore ` and :ref:`ZookeeperStore `) use a unique token to recognize the true owner of the lock. This token is stored in the :class:`Symfony\\Component\\Lock\\Key` object and is used internally by @@ -375,7 +409,8 @@ Expiring Stores ~~~~~~~~~~~~~~~ Expiring stores (:ref:`MemcachedStore `, -:ref:`PdoStore ` and :ref:`RedisStore `) +:ref:`MongoDbStore `, :ref:`PdoStore ` and +:ref:`RedisStore `) guarantee that the lock is acquired only for the defined duration of time. If the task takes longer to be accomplished, then the lock can be released by the store and acquired by someone else. @@ -492,6 +527,54 @@ method uses the Memcached's ``flush()`` method which purges and removes everythi The method ``flush()`` must not be called, or locks should be stored in a dedicated Memcached service away from Cache. +MongoDbStore +~~~~~~~~~~~~ + +.. caution:: + + The locked resouce name is indexed in the ``_id`` field of the + lock collection. + An indexed field's value in MongoDB can be a maximum of 1024 bytes in + length inclusive of structural overhead. + +For more details see: https://docs.mongodb.com/manual/reference/limits/#Index-Key-Limit + +A TTL index MUST BE used on MongoDB 2.2+ to automatically clean up expired locks. + +Such an index can be created manually: + +.. code-block:: javascript + + db.lock.ensureIndex( + { "expires_at": 1 }, + { "expireAfterSeconds": 0 } + ) + +Alternatively, the method ``MongoDbStore::createTtlIndex(int $expireAfterSeconds = 0)`` +can be called once to create the TTL index during database setup. + +For more details see: http://docs.mongodb.org/manual/tutorial/expire-data/ + +.. tip:: + + ``MongoDbStore`` will attempt to automatically create a TTL index on + mongodb 2.2+. It's recommended to set constructor option + ``gcProbablity = 0.0`` to disable this behaviour if you have manually + dealt with TTL index creation. + +.. caution:: + + This store relies on all php application and database nodes to have + synchronized clocks for lock expiry to occur at the correct time. + To ensure locks don't expire prematurely; the lock TTL should be set + with enough extra time in ``expireAfterSeconds`` to account for any + clock drift between nodes. + +``writeConcern``, ``readConcern`` and ``readPreference`` are not specified by +MongoDbStore meaning the collection's settings will take effect. + +For more details see: https://docs.mongodb.com/manual/applications/replication/ + PdoStore ~~~~~~~~~~ @@ -612,6 +695,7 @@ are still running. .. _`ACID`: https://en.wikipedia.org/wiki/ACID .. _`locks`: https://en.wikipedia.org/wiki/Lock_(computer_science) +.. _`mongodb/mongodb`: https://packagist.org/packages/mongodb/mongodb .. _Packagist: https://packagist.org/packages/symfony/lock .. _`PHP semaphore functions`: http://php.net/manual/en/book.sem.php .. _`PDO`: https://php.net/pdo From 4b2007e6dcfa1d4cd7f1c7ed97e2192960a5352a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 29 Mar 2019 10:27:45 +0100 Subject: [PATCH 058/499] Documented the new Unique constraint --- reference/constraints.rst | 1 + reference/constraints/Collection.rst | 5 ++ reference/constraints/Unique.rst | 113 +++++++++++++++++++++++++ reference/constraints/UniqueEntity.rst | 5 ++ reference/constraints/map.rst.inc | 1 + 5 files changed, 125 insertions(+) create mode 100644 reference/constraints/Unique.rst diff --git a/reference/constraints.rst b/reference/constraints.rst index d81a4eefd37..d068494b8a2 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -31,6 +31,7 @@ Validation Constraints Reference constraints/GreaterThanOrEqual constraints/Range constraints/DivisibleBy + constraints/Unique constraints/Date constraints/DateTime diff --git a/reference/constraints/Collection.rst b/reference/constraints/Collection.rst index daf59746588..12dc1e2f07a 100644 --- a/reference/constraints/Collection.rst +++ b/reference/constraints/Collection.rst @@ -11,6 +11,11 @@ constraint. This constraint can also make sure that certain collection keys are present and that extra keys are not present. +.. seealso:: + + If you want to validate that all the elements of the collection are unique + use the :doc:`Unique constraint `. + ========== =================================================================== Applies to :ref:`property or method ` Options - `allowExtraFields`_ diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst new file mode 100644 index 00000000000..681c4dc18b6 --- /dev/null +++ b/reference/constraints/Unique.rst @@ -0,0 +1,113 @@ +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). + +.. seealso:: + + If you want to apply different validation constraints to the elements of a + collection or want to make sure that certain collection keys are present, + use the :doc:`Collection constraint `. + +.. seealso:: + + If you want to validate that the value of an entity property is unique among + all entities of the same type (e.g. the registration email of all users) use + the :doc:`UniqueEntity constraint `. + +========== =================================================================== +Applies to :ref:`property or method ` +Options - `groups`_ + - `message`_ + - `payload`_ +Class :class:`Symfony\\Component\\Validator\\Constraints\\Unique` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\UniqueValidator` +========== =================================================================== + +Basic Usage +----------- + +This constraint can be applied to any property of type ``array`` or +``\Traversable``. In the following example, ``$contactEmails`` is an array of +strings: + +.. configuration-block:: + + .. code-block:: php-annotations + + // 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 + App\Entity\Person: + properties: + contactEmails: + - Unique: ~ + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('contactEmails', new Assert\Unique()); + } + } + +Options +------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This collection should contain only unique elements.`` + +This is the message that will be shown if at least one element is repeated in +the collection. + +You can use the following parameters in this message: + +============================= ================================================ +Parameter Description +============================= ================================================ +``{{ value }}`` The repeated value +============================= ================================================ + +.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/UniqueEntity.rst b/reference/constraints/UniqueEntity.rst index f6c4ddf8bce..2d2b658dee1 100644 --- a/reference/constraints/UniqueEntity.rst +++ b/reference/constraints/UniqueEntity.rst @@ -5,6 +5,11 @@ Validates that a particular field (or fields) in a Doctrine entity is (are) unique. This is commonly used, for example, to prevent a new user to register using an email address that already exists in the system. +.. seealso:: + + If you want to validate that all the elements of the collection are unique + use the :doc:`Unique constraint `. + ========== =================================================================== Applies to :ref:`class ` Options - `em`_ diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index 4f95a168242..1ccfc1ec691 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -37,6 +37,7 @@ Comparison Constraints * :doc:`GreaterThanOrEqual ` * :doc:`Range ` * :doc:`DivisibleBy ` +* :doc:`Unique ` Date Constraints ~~~~~~~~~~~~~~~~ From 52a7157fe131970043d6372eb9d65aceeca907c2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 1 Apr 2019 15:18:34 +0200 Subject: [PATCH 059/499] [Messenger] Rename the messenger:consume-messages command --- messenger.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/messenger.rst b/messenger.rst index 698b375153b..b17cb6f1549 100644 --- a/messenger.rst +++ b/messenger.rst @@ -410,19 +410,23 @@ while still having them passed to their respective handler: Consuming Messages ------------------ -Once your messages have been routed, you will like to consume your messages in most -of the cases. To do so, you can use the ``messenger:consume-messages`` command -like this: +Once your messages have been routed, you will like to consume your messages in +most of the cases. To do so, use the ``messenger:consume`` command like this: .. code-block:: terminal - $ php bin/console messenger:consume-messages amqp + $ php bin/console messenger:consume amqp The first argument is the receiver's service name. It might have been created by your ``transports`` configuration or it can be your own receiver. It also requires a ``--bus`` option in case you have multiple buses configured, which is the name of the bus to which received messages should be dispatched. +.. versionadded:: 4.3 + + The ``messenger:consume`` command was renamed in Symfony 4.3 (previously it + was called ``messenger:consume-messages``). + Middleware ---------- From 47e1741ffceb311bf108db8577a31c506f2cb43d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 1 Apr 2019 16:03:42 +0200 Subject: [PATCH 060/499] Minor tweaks --- components/lock.rst | 63 +++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/components/lock.rst b/components/lock.rst index 66748fa5707..decf6bc4d6b 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -224,29 +224,29 @@ MongoDbStore .. versionadded:: 4.3 The MongoDbStore was introduced 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:: +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:: use Symfony\Component\Lock\Store\MongoDbStore; $mongoClient = new \MongoDB\Client('mongo://localhost/'); - $options = array( + $options = [ 'database' => 'my-app', - ); + ]; $store = new MongoDbStore($mongoClient, $options); The ``MongoDbStore`` takes the following ``$options``: -============ ========= ======================================================================== -Option Default Description -============ ========= ======================================================================== -database The name of the database [Mandatory] -collection ``lock`` The name of the collection -gcProbablity ``0.001`` Should a TTL Index be created expressed as a probability from 0.0 to 1.0 -============ ========= ======================================================================== +============ ========= ======================================================================== +Option Default Description +============ ========= ======================================================================== +database The name of the database [Mandatory] +collection ``lock`` The name of the collection +gcProbablity ``0.001`` Should a TTL Index be created expressed as a probability from 0.0 to 1.0 +============ ========= ======================================================================== .. _lock-store-pdo: @@ -532,15 +532,11 @@ MongoDbStore .. caution:: - The locked resouce name is indexed in the ``_id`` field of the - lock collection. - An indexed field's value in MongoDB can be a maximum of 1024 bytes in - length inclusive of structural overhead. - -For more details see: https://docs.mongodb.com/manual/reference/limits/#Index-Key-Limit + The locked resource name is indexed in the ``_id`` field of the lock + collection. Beware that in MongoDB an indexed field's value can be + `a maximum of 1024 bytes in length`_ inclusive of structural overhead. A TTL index MUST BE used on MongoDB 2.2+ to automatically clean up expired locks. - Such an index can be created manually: .. code-block:: javascript @@ -551,29 +547,25 @@ Such an index can be created manually: ) Alternatively, the method ``MongoDbStore::createTtlIndex(int $expireAfterSeconds = 0)`` -can be called once to create the TTL index during database setup. - -For more details see: http://docs.mongodb.org/manual/tutorial/expire-data/ +can be called once to create the TTL index during database setup. Read more +about `Expire Data from Collections by Setting TTL`_ in MongoDB. .. tip:: - ``MongoDbStore`` will attempt to automatically create a TTL index on - mongodb 2.2+. It's recommended to set constructor option - ``gcProbablity = 0.0`` to disable this behaviour if you have manually - dealt with TTL index creation. + ``MongoDbStore`` will attempt to automatically create a TTL index on MongoDB + 2.2+. It's recommended to set constructor option ``gcProbablity = 0.0`` to + disable this behavior if you have manually dealt with TTL index creation. .. caution:: - This store relies on all php application and database nodes to have - synchronized clocks for lock expiry to occur at the correct time. - To ensure locks don't expire prematurely; the lock TTL should be set - with enough extra time in ``expireAfterSeconds`` to account for any - clock drift between nodes. + This store relies on all PHP application and database nodes to have + synchronized clocks for lock expiry to occur at the correct time. To ensure + locks don't expire prematurely; the lock TTL should be set with enough extra + time in ``expireAfterSeconds`` to account for any clock drift between nodes. ``writeConcern``, ``readConcern`` and ``readPreference`` are not specified by -MongoDbStore meaning the collection's settings will take effect. - -For more details see: https://docs.mongodb.com/manual/applications/replication/ +MongoDbStore meaning the collection's settings will take effect. Read more +about `Replica Set Read and Write Semantics`_ in MongoDB. PdoStore ~~~~~~~~~~ @@ -702,3 +694,6 @@ are still running. .. _`Doctrine DBAL Connection`: https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Connection.php .. _`Data Source Name (DSN)`: https://en.wikipedia.org/wiki/Data_source_name .. _`ZooKeeper`: https://zookeeper.apache.org/ +.. _`a maximum of 1024 bytes in length`: https://docs.mongodb.com/manual/reference/limits/#Index-Key-Limit +.. _`Expire Data from Collections by Setting TTL`: https://docs.mongodb.com/manual/tutorial/expire-data/ +.. _`Replica Set Read and Write Semantics`: https://docs.mongodb.com/manual/applications/replication/ From 6b445673f77f1a3eb344a9c9c1188145dc131e87 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 1 Apr 2019 20:55:52 +0200 Subject: [PATCH 061/499] added blank line and typo fix --- components/lock.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/lock.rst b/components/lock.rst index decf6bc4d6b..141ea4b101b 100644 --- a/components/lock.rst +++ b/components/lock.rst @@ -222,7 +222,8 @@ MongoDbStore ~~~~~~~~~~~~ .. versionadded:: 4.3 - The MongoDbStore was introduced Symfony 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 From 8c4b4c0c6ee2437597a45bf535cb1a5b33ae8d88 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 28 Mar 2019 10:31:31 +0100 Subject: [PATCH 062/499] more consistency for master --- configuration/environment_variables.rst | 2 +- console/coloring.rst | 1 + form/form_themes.rst | 4 ++-- reference/constraints/Json.rst | 4 ++-- reference/forms/types/button.rst | 6 ++---- reference/forms/types/date.rst | 2 +- .../attr_translation_parameters.rst.inc | 18 ++++++++---------- .../help_translation_parameters.rst.inc | 14 ++++++-------- .../label_translation_parameters.rst.inc | 14 ++++++-------- reference/forms/types/reset.rst | 14 ++++++-------- reference/forms/types/submit.rst | 14 ++++++-------- routing.rst | 1 + service_container/alias_private.rst | 2 +- 13 files changed, 43 insertions(+), 53 deletions(-) diff --git a/configuration/environment_variables.rst b/configuration/environment_variables.rst index 11e23624eb5..50a2bd77daf 100644 --- a/configuration/environment_variables.rst +++ b/configuration/environment_variables.rst @@ -642,7 +642,7 @@ Symfony provides the following env var processors: http://symfony.com/schema/dic/services/services-1.0.xsd"> - + diff --git a/console/coloring.rst b/console/coloring.rst index b9a65cefc1b..2963fefa682 100644 --- a/console/coloring.rst +++ b/console/coloring.rst @@ -78,6 +78,7 @@ 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 diff --git a/form/form_themes.rst b/form/form_themes.rst index 24bd5f4bd3c..ea3ccf9e366 100644 --- a/form/form_themes.rst +++ b/form/form_themes.rst @@ -289,9 +289,9 @@ field without having to :doc:`create a custom form type add('name', TextType::class, array( + $builder->add('name', TextType::class, [ 'block_prefix' => 'wrapped_text', - )); + ]); } .. versionadded:: 4.3 diff --git a/reference/constraints/Json.rst b/reference/constraints/Json.rst index 085fbe718c9..1fdcaaffd12 100644 --- a/reference/constraints/Json.rst +++ b/reference/constraints/Json.rst @@ -78,9 +78,9 @@ The ``Json`` constraint can be applied to a property or a "getter" method: public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint('chapters', new Assert\Json(array( + $metadata->addPropertyConstraint('chapters', new Assert\Json([ 'message' => 'You\'ve entered an invalid Json.', - ))); + ])); } } diff --git a/reference/forms/types/button.rst b/reference/forms/types/button.rst index 5ce297acba8..d009b80235e 100644 --- a/reference/forms/types/button.rst +++ b/reference/forms/types/button.rst @@ -71,12 +71,10 @@ Given this translation message: .. code-block:: yaml - # translations/messages.en.yml + # translations/messages.en.yaml form.order.submit_to_company: 'Send an order to %company%' -You can specify the placeholder values as follows: - -.. code-block:: php +You can specify the placeholder values as follows:: use Symfony\Component\Form\Extension\Core\Type\ButtonType; // ... diff --git a/reference/forms/types/date.rst b/reference/forms/types/date.rst index 3dab11ba1e7..6e2be4140e3 100644 --- a/reference/forms/types/date.rst +++ b/reference/forms/types/date.rst @@ -171,7 +171,7 @@ values for the year, month and day fields:: .. include:: /reference/forms/types/options/date_format.rst.inc -.. versionadded:: 4.3 +.. deprecated:: 4.3 Using the ``format`` option when the ``html5`` option is enabled is deprecated since Symfony 4.3. diff --git a/reference/forms/types/options/attr_translation_parameters.rst.inc b/reference/forms/types/options/attr_translation_parameters.rst.inc index bda010127c6..98326ba4abe 100644 --- a/reference/forms/types/options/attr_translation_parameters.rst.inc +++ b/reference/forms/types/options/attr_translation_parameters.rst.inc @@ -16,23 +16,21 @@ Given this translation message: .. code-block:: yaml - # translations/messages.en.yml + # translations/messages.en.yaml form.order.id.placeholder: 'Enter unique identifier of the order to %company%' form.order.id.title: 'This will be the reference in communications with %company%' -You can specify the placeholder values as follows: +You can specify the placeholder values as follows:: -.. code-block:: php - - $builder->add('id', null, array( - 'attr' => array( + $builder->add('id', null, [ + 'attr' => [ 'placeholder' => 'form.order.id.placeholder', 'title' => 'form.order.id.title', - ), + ], 'attr_translation_parameters' => [ - '%company%' => 'ACME Inc.' - ] - )); + '%company%' => 'ACME Inc.', + ], + ]); The ``attr_translation_parameters`` option of children fields is merged with the same option of their parents, so children can reuse and/or override any of the diff --git a/reference/forms/types/options/help_translation_parameters.rst.inc b/reference/forms/types/options/help_translation_parameters.rst.inc index 44723597127..4294fb2b185 100644 --- a/reference/forms/types/options/help_translation_parameters.rst.inc +++ b/reference/forms/types/options/help_translation_parameters.rst.inc @@ -15,19 +15,17 @@ Given this translation message: .. code-block:: yaml - # translations/messages.en.yml + # translations/messages.en.yaml form.order.id.help: 'This will be the reference in communications with %company%' -You can specify the placeholder values as follows: +You can specify the placeholder values as follows:: -.. code-block:: php - - $builder->add('id', null, array( + $builder->add('id', null, [ 'help' => 'form.order.id.help', 'help_translation_parameters' => [ - '%company%' => 'ACME Inc.' - ] - )); + '%company%' => 'ACME Inc.', + ], + ]); The ``help_translation_parameters`` option of children fields is merged with the same option of their parents, so children can reuse and/or override any of the diff --git a/reference/forms/types/options/label_translation_parameters.rst.inc b/reference/forms/types/options/label_translation_parameters.rst.inc index f7903c5a473..443c6706f14 100644 --- a/reference/forms/types/options/label_translation_parameters.rst.inc +++ b/reference/forms/types/options/label_translation_parameters.rst.inc @@ -15,19 +15,17 @@ Given this translation message: .. code-block:: yaml - # translations/messages.en.yml + # translations/messages.en.yaml form.order.id: 'Identifier of the order to %company%' -You can specify the placeholder values as follows: +You can specify the placeholder values as follows:: -.. code-block:: php - - $builder->add('id', null, array( + $builder->add('id', null, [ 'label' => 'form.order.id', 'label_translation_parameters' => [ - '%company%' => 'ACME Inc.' - ] - )); + '%company%' => 'ACME Inc.', + ], + ]); The ``label_translation_parameters`` option of children fields is merged with the same option of their parents, so children can reuse and/or override any of diff --git a/reference/forms/types/reset.rst b/reference/forms/types/reset.rst index a4b7642b5a6..a9639e03bc7 100644 --- a/reference/forms/types/reset.rst +++ b/reference/forms/types/reset.rst @@ -61,22 +61,20 @@ Given this translation message: .. code-block:: yaml - # translations/messages.en.yml + # translations/messages.en.yaml form.order.reset: 'Reset an order to %company%' -You can specify the placeholder values as follows: - -.. code-block:: php +You can specify the placeholder values as follows:: use Symfony\Component\Form\Extension\Core\Type\ResetType; // ... - $builder->add('send', ResetType::class, array( + $builder->add('send', ResetType::class, [ 'label' => 'form.order.reset', - 'label_translation_parameters' => array( + 'label_translation_parameters' => [ '%company%' => 'ACME Inc.', - ), - )); + ], + ]); The ``label_translation_parameters`` option of buttons is merged with the same option of its parents, so buttons can reuse and/or override any of the parent diff --git a/reference/forms/types/submit.rst b/reference/forms/types/submit.rst index 7e1bac1bfb1..7a0672ea6c2 100644 --- a/reference/forms/types/submit.rst +++ b/reference/forms/types/submit.rst @@ -74,22 +74,20 @@ Given this translation message: .. code-block:: yaml - # translations/messages.en.yml + # translations/messages.en.yaml form.order.submit_to_company: 'Send an order to %company%' -You can specify the placeholder values as follows: - -.. code-block:: php +You can specify the placeholder values as follows:: use Symfony\Component\Form\Extension\Core\Type\SubmitType; // ... - $builder->add('send', SubmitType::class, array( + $builder->add('send', SubmitType::class, [ 'label' => 'form.order.submit_to_company', - 'label_translation_parameters' => array( + 'label_translation_parameters' => [ '%company%' => 'ACME Inc.', - ), - )); + ], + ]); The ``label_translation_parameters`` option of buttons is merged with the same option of its parents, so buttons can reuse and/or override any of the parent diff --git a/routing.rst b/routing.rst index 9ee80b95c4a..1b807ec3797 100644 --- a/routing.rst +++ b/routing.rst @@ -529,6 +529,7 @@ 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. diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst index 3e88b991d33..13c9da828c7 100644 --- a/service_container/alias_private.rst +++ b/service_container/alias_private.rst @@ -175,7 +175,7 @@ or you decided not to maintain it anymore), you can deprecate its definition: - + The "%alias_id%" service alias is deprecated. Don't use it anymore. From fd912c05f1a23bf566891c0f737fa5b9c12bd9d9 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 1 Apr 2019 22:35:07 +0200 Subject: [PATCH 063/499] small tweaks for Symfony server --- setup/symfony_server.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup/symfony_server.rst b/setup/symfony_server.rst index 5f991b827fa..ca9933b4369 100644 --- a/setup/symfony_server.rst +++ b/setup/symfony_server.rst @@ -55,7 +55,7 @@ run the Symfony server in the background: Enabling TLS ------------ -Browsing the secure version of your apps locally is important to detect +Browsing the secure version of your applications locally is important to detect problems with mixed content early, and to run libraries that only run in HTTPS. Traditionally this has been painful and complicated to set up, but the Symfony server automates everything. First, run this command: @@ -167,7 +167,7 @@ local IP. However, sometimes it is preferable to associate a domain name to them * It's more convenient when you work continuously on the same project because port numbers can change but domains don't; * The behavior of some applications depend on their domains/subdomains; -* To have stable endpoints, such as the local redirection URL for Oauth2. +* To have stable endpoints, such as the local redirection URL for OAuth2. Setting up the Local Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -279,7 +279,7 @@ commands from the Symfony server: # creates a new project based on symfony/website-skeleton $ symfony new --full my_project_name - # creates a new project based on the Symfony Demo application + # creates a new project based on symfony/demo $ symfony new --demo my_project_name SymfonyCloud Integration From 6eec07b43346b50299cac762e94dc6b7a432ff4b Mon Sep 17 00:00:00 2001 From: Renan Taranto Date: Tue, 2 Apr 2019 22:24:00 -0300 Subject: [PATCH 064/499] [Validator] Document the "normalizer" option --- reference/constraints/Email.rst | 2 ++ reference/constraints/Ip.rst | 2 ++ reference/constraints/Length.rst | 2 ++ reference/constraints/NotBlank.rst | 12 ++++++++++++ reference/constraints/Regex.rst | 2 ++ reference/constraints/Url.rst | 2 ++ reference/constraints/Uuid.rst | 2 ++ reference/constraints/_normalizer-option.rst.inc | 10 ++++++++++ 8 files changed, 34 insertions(+) create mode 100644 reference/constraints/_normalizer-option.rst.inc diff --git a/reference/constraints/Email.rst b/reference/constraints/Email.rst index 41c0e76f24f..9cc865c66be 100644 --- a/reference/constraints/Email.rst +++ b/reference/constraints/Email.rst @@ -11,6 +11,7 @@ Options - `checkHost`_ - `groups`_ - `message`_ - `mode`_ + - `normalizer`_ - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Email` Validator :class:`Symfony\\Component\\Validator\\Constraints\\EmailValidator` @@ -167,6 +168,7 @@ html5 This matches the pattern used for the `HTML5 email input element`_. +.. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc .. _egulias/email-validator: https://packagist.org/packages/egulias/email-validator diff --git a/reference/constraints/Ip.rst b/reference/constraints/Ip.rst index fcbb4057ff4..f04a36105f4 100644 --- a/reference/constraints/Ip.rst +++ b/reference/constraints/Ip.rst @@ -9,6 +9,7 @@ IPv6 and many other combinations. Applies to :ref:`property or method ` Options - `groups`_ - `message`_ + - `normalizer`_ - `payload`_ - `version`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Ip` @@ -96,6 +97,7 @@ Parameter Description ``{{ value }}`` The current (invalid) value =============== ============================================================== +.. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc version diff --git a/reference/constraints/Length.rst b/reference/constraints/Length.rst index ea96d7efb64..c0947326333 100644 --- a/reference/constraints/Length.rst +++ b/reference/constraints/Length.rst @@ -19,6 +19,7 @@ Options - `charset`_ - `maxMessage`_ - `min`_ - `minMessage`_ + - `normalizer`_ - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Length` Validator :class:`Symfony\\Component\\Validator\\Constraints\\LengthValidator` @@ -213,4 +214,5 @@ Parameter Description ``{{ value }}`` The current (invalid) value ================= ============================================================ +.. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index 1c465e7c334..3783df1c5d7 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -11,6 +11,7 @@ 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` @@ -110,4 +111,15 @@ Parameter Description ``{{ value }}`` The current (invalid) value =============== ============================================================== +normalizer +~~~~~~~~~~ + +**type**: ``string`` **default**: ``null`` + +If the given value is a ``string``, this option can be used to normalize it while +checking if it is valid. A ``callable`` must be passed. + +For example, you may want to use :phpfunction:`trim` to ignore leading and +trailing whitespace during validation. + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Regex.rst b/reference/constraints/Regex.rst index 953bd8533e8..4363b8a78cb 100644 --- a/reference/constraints/Regex.rst +++ b/reference/constraints/Regex.rst @@ -10,6 +10,7 @@ Options - `groups`_ - `match`_ - `message`_ - `pattern`_ + - `normalizer`_ - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Regex` Validator :class:`Symfony\\Component\\Validator\\Constraints\\RegexValidator` @@ -287,4 +288,5 @@ does *not* match this regular expression (via the :phpfunction:`preg_match` PHP function). However, if `match`_ is set to false, then validation will fail if the input string *does* match this pattern. +.. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Url.rst b/reference/constraints/Url.rst index 2f41a47b01f..558545ac21a 100644 --- a/reference/constraints/Url.rst +++ b/reference/constraints/Url.rst @@ -9,6 +9,7 @@ Options - `checkDNS`_ - `dnsMessage`_ - `groups`_ - `message`_ + - `normalizer`_ - `payload`_ - `protocols`_ - `relativeProtocol`_ @@ -319,6 +320,7 @@ Parameter Description } } +.. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc protocols diff --git a/reference/constraints/Uuid.rst b/reference/constraints/Uuid.rst index 1c84756223f..386803ab2e8 100644 --- a/reference/constraints/Uuid.rst +++ b/reference/constraints/Uuid.rst @@ -10,6 +10,7 @@ UUID versions can also be restricted using a whitelist. Applies to :ref:`property or method ` Options - `groups`_ - `message`_ + - `normalizer`_ - `payload`_ - `strict`_ - `versions`_ @@ -98,6 +99,7 @@ Parameter Description ``{{ value }}`` The current (invalid) value =============== ============================================================== +.. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc strict diff --git a/reference/constraints/_normalizer-option.rst.inc b/reference/constraints/_normalizer-option.rst.inc new file mode 100644 index 00000000000..262d7e41177 --- /dev/null +++ b/reference/constraints/_normalizer-option.rst.inc @@ -0,0 +1,10 @@ +normalizer +~~~~~~~~~~ + +**type**: ``string`` **default**: ``null`` + +This option allows a ``callable`` to be passed in order to normalize the given +value while checking if it is valid. + +For example, you may want to use :phpfunction:`trim` to ignore leading and +trailing whitespace during validation. From 8022292205dc5ae92fc246f81c1dc4e44dd5d5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= Date: Sun, 31 Mar 2019 19:21:24 +0200 Subject: [PATCH 065/499] [Validator] Add docs for number constraints --- reference/constraints.rst | 5 ++ reference/constraints/Negative.rst | 106 ++++++++++++++++++++++ reference/constraints/NegativeOrZero.rst | 107 +++++++++++++++++++++++ reference/constraints/Positive.rst | 106 ++++++++++++++++++++++ reference/constraints/PositiveOrZero.rst | 107 +++++++++++++++++++++++ reference/constraints/map.rst.inc | 7 ++ 6 files changed, 438 insertions(+) create mode 100644 reference/constraints/Negative.rst create mode 100644 reference/constraints/NegativeOrZero.rst create mode 100644 reference/constraints/Positive.rst create mode 100644 reference/constraints/PositiveOrZero.rst diff --git a/reference/constraints.rst b/reference/constraints.rst index d81a4eefd37..2e30e3ee19f 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -32,6 +32,11 @@ Validation Constraints Reference constraints/Range constraints/DivisibleBy + constraints/Positive + constraints/PositiveOrZero + constraints/Negative + constraints/NegativeOrZero + constraints/Date constraints/DateTime constraints/Time diff --git a/reference/constraints/Negative.rst b/reference/constraints/Negative.rst new file mode 100644 index 00000000000..0a3e91c4fce --- /dev/null +++ b/reference/constraints/Negative.rst @@ -0,0 +1,106 @@ +Negative +======== + +.. versionadded:: 4.3 + + The ``Negative`` constraint was introduced in Symfony 4.3. + +Validates that a value is a negative number. To force that a value is a negative +number or equal to zero, see :doc:`/reference/constraints/NegativeOrZero`. +To force a value is positive, see :doc:`/reference/constraints/Positive`. + +========== =================================================================== +Applies to :ref:`property or method ` +Options - `groups`_ + - `message`_ + - `payload`_ +Class :class:`Symfony\\Component\\Validator\\Constraints\\Negative` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\LesserThanValidator` +========== =================================================================== + +Basic Usage +----------- + +The following constraint ensure that: + +* the ``withdraw`` of a bankaccount ``TransferItem`` is a negative number (lesser than zero) + +.. configuration-block:: + + .. code-block:: php-annotations + + // 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 + App\Entity\TransferItem: + properties: + withdraw: + - Negative + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/TransferItem.php + namespace App\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class TransferItem + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('withdraw', new Assert\Negative()); + } + } + +Available Options +----------------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be negative.`` + +The default message supplied when the value is not less than zero. + +You can use the following parameters in this message: + +============================= ================================================ +Parameter Description +============================= ================================================ +``{{ compared_value }}`` Always zero +``{{ compared_value_type }}`` The expected value type +``{{ value }}`` The current (invalid) value +============================= ================================================ + +.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/NegativeOrZero.rst b/reference/constraints/NegativeOrZero.rst new file mode 100644 index 00000000000..7d0dc452a5f --- /dev/null +++ b/reference/constraints/NegativeOrZero.rst @@ -0,0 +1,107 @@ +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. To force that a value +is only a negative number, see :doc:`/reference/constraints/Negative`. +To force a value is positive or equal to zero, +see :doc:`/reference/constraints/PositiveOrZero`. + +========== =================================================================== +Applies to :ref:`property or method ` +Options - `groups`_ + - `message`_ + - `payload`_ +Class :class:`Symfony\\Component\\Validator\\Constraints\\NegativeOrZero` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\LesserThanOrEqualValidator` +========== =================================================================== + +Basic Usage +----------- + +The following constraint ensure that: + +* the ``level`` of a ``UnderGroundGarage`` is a negative number or equal to zero + +.. configuration-block:: + + .. code-block:: php-annotations + + // 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 + App\Entity\UnderGroundGarage: + properties: + level: + - NegativeOrZero + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/UnderGroundGarage.php + namespace App\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class UnderGroundGarage + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('level', new Assert\NegativeOrZero()); + } + } + +Available Options +----------------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be either negative or zero.`` + +The default message supplied when the value is not less than or equal to zero. + +You can use the following parameters in this message: + +============================= ================================================ +Parameter Description +============================= ================================================ +``{{ compared_value }}`` Always zero +``{{ compared_value_type }}`` The expected value type +``{{ value }}`` The current (invalid) value +============================= ================================================ + +.. include:: /reference/constraints/_payload-option.rst.inc \ No newline at end of file diff --git a/reference/constraints/Positive.rst b/reference/constraints/Positive.rst new file mode 100644 index 00000000000..1897758c3bf --- /dev/null +++ b/reference/constraints/Positive.rst @@ -0,0 +1,106 @@ +Positive +======== + +.. versionadded:: 4.3 + + The ``Positive`` constraint was introduced in Symfony 4.3. + +Validates that a value is a positive number. To force that a value is positive +number or equal to zero, see :doc:`/reference/constraints/PositiveOrZero`. +To force a value is negative, see :doc:`/reference/constraints/Negative`. + +========== =================================================================== +Applies to :ref:`property or method ` +Options - `groups`_ + - `message`_ + - `payload`_ +Class :class:`Symfony\\Component\\Validator\\Constraints\\Positive` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanValidator` +========== =================================================================== + +Basic Usage +----------- + +The following constraint ensure that: + +* the ``income`` of an ``Employee`` is a positive number (greater than zero) + +.. configuration-block:: + + .. code-block:: php-annotations + + // 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 + App\Entity\Employee: + properties: + income: + - Positive + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/Employee.php + namespace App\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Employee + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('income', new Assert\Positive()); + } + } + +Available Options +----------------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be positive.`` + +The default message supplied when the value is not greater than zero. + +You can use the following parameters in this message: + +============================= ================================================ +Parameter Description +============================= ================================================ +``{{ compared_value }}`` Always zero +``{{ compared_value_type }}`` The expected value type +``{{ value }}`` The current (invalid) value +============================= ================================================ + +.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/PositiveOrZero.rst b/reference/constraints/PositiveOrZero.rst new file mode 100644 index 00000000000..44e736ee044 --- /dev/null +++ b/reference/constraints/PositiveOrZero.rst @@ -0,0 +1,107 @@ +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. To force that +a value is only a positiven umber, see :doc:`/reference/constraints/Positive`. +To force a value is negative or equal to zero, +see :doc:`/reference/constraints/NegativeOrZero`. + +========== =================================================================== +Applies to :ref:`property or method ` +Options - `groups`_ + - `message`_ + - `payload`_ +Class :class:`Symfony\\Component\\Validator\\Constraints\\PositiveOrZero` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqualValidator` +========== =================================================================== + +Basic Usage +----------- + +The following constraint ensure that: + +* the number of ``siblings`` of a ``Person`` is positive or zero + +.. configuration-block:: + + .. code-block:: php-annotations + + // 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 + App\Entity\Person: + properties: + siblings: + - PositiveOrZero + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/Person.php + namespace App\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Person + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('siblings', new Assert\PositiveOrZero()); + } + } + +Available Options +----------------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This value should be either positive or zero.`` + +The default message supplied when the value is not greater than or equal to zero. + +You can use the following parameters in this message: + +============================= ================================================ +Parameter Description +============================= ================================================ +``{{ compared_value }}`` Always zero +``{{ compared_value_type }}`` The expected value type +``{{ value }}`` The current (invalid) value +============================= ================================================ + +.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index 4f95a168242..5402a2fd0d2 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -38,6 +38,13 @@ Comparison Constraints * :doc:`Range ` * :doc:`DivisibleBy ` +Number Constraints +~~~~~~~~~~~~~~~~~~ +* :doc:`Positive ` +* :doc:`PositiveOrZero ` +* :doc:`Negative ` +* :doc:`NegativeOrZero ` + Date Constraints ~~~~~~~~~~~~~~~~ From 77c8b09efb53ad1e718d795f5e5be635ab4a982d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Apr 2019 09:25:50 +0200 Subject: [PATCH 066/499] Minor tweaks --- reference/constraints/Negative.rst | 11 +++++------ reference/constraints/NegativeOrZero.rst | 13 +++++-------- reference/constraints/Positive.rst | 11 +++++------ reference/constraints/PositiveOrZero.rst | 11 ++++------- 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/reference/constraints/Negative.rst b/reference/constraints/Negative.rst index 0a3e91c4fce..0a0d53002a3 100644 --- a/reference/constraints/Negative.rst +++ b/reference/constraints/Negative.rst @@ -5,9 +5,9 @@ Negative The ``Negative`` constraint was introduced in Symfony 4.3. -Validates that a value is a negative number. To force that a value is a negative -number or equal to zero, see :doc:`/reference/constraints/NegativeOrZero`. -To force a value is positive, see :doc:`/reference/constraints/Positive`. +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. ========== =================================================================== Applies to :ref:`property or method ` @@ -21,9 +21,8 @@ Validator :class:`Symfony\\Component\\Validator\\Constraints\\LesserThanValida Basic Usage ----------- -The following constraint ensure that: - -* the ``withdraw`` of a bankaccount ``TransferItem`` is a negative number (lesser than zero) +The following constraint ensures that the ``withdraw`` of a bank account +``TransferItem`` is a negative number (lesser than zero): .. configuration-block:: diff --git a/reference/constraints/NegativeOrZero.rst b/reference/constraints/NegativeOrZero.rst index 7d0dc452a5f..6b92c8900d2 100644 --- a/reference/constraints/NegativeOrZero.rst +++ b/reference/constraints/NegativeOrZero.rst @@ -5,10 +5,8 @@ NegativeOrZero The ``NegativeOrZero`` constraint was introduced in Symfony 4.3. -Validates that a value is a negative number or equal to zero. To force that a value -is only a negative number, see :doc:`/reference/constraints/Negative`. -To force a value is positive or equal to zero, -see :doc:`/reference/constraints/PositiveOrZero`. +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. ========== =================================================================== Applies to :ref:`property or method ` @@ -22,9 +20,8 @@ Validator :class:`Symfony\\Component\\Validator\\Constraints\\LesserThanOrEqua Basic Usage ----------- -The following constraint ensure that: - -* the ``level`` of a ``UnderGroundGarage`` is a negative number or equal to zero +The following constraint ensures that the ``level`` of a ``UnderGroundGarage`` +is a negative number or equal to zero: .. configuration-block:: @@ -104,4 +101,4 @@ Parameter Description ``{{ value }}`` The current (invalid) value ============================= ================================================ -.. include:: /reference/constraints/_payload-option.rst.inc \ No newline at end of file +.. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Positive.rst b/reference/constraints/Positive.rst index 1897758c3bf..28633551f60 100644 --- a/reference/constraints/Positive.rst +++ b/reference/constraints/Positive.rst @@ -5,9 +5,9 @@ Positive The ``Positive`` constraint was introduced in Symfony 4.3. -Validates that a value is a positive number. To force that a value is positive -number or equal to zero, see :doc:`/reference/constraints/PositiveOrZero`. -To force a value is negative, see :doc:`/reference/constraints/Negative`. +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. ========== =================================================================== Applies to :ref:`property or method ` @@ -21,9 +21,8 @@ Validator :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanValid Basic Usage ----------- -The following constraint ensure that: - -* the ``income`` of an ``Employee`` is a positive number (greater than zero) +The following constraint ensures that the ``income`` of an ``Employee`` is a +positive number (greater than zero): .. configuration-block:: diff --git a/reference/constraints/PositiveOrZero.rst b/reference/constraints/PositiveOrZero.rst index 44e736ee044..7d668598e96 100644 --- a/reference/constraints/PositiveOrZero.rst +++ b/reference/constraints/PositiveOrZero.rst @@ -5,10 +5,8 @@ PositiveOrZero The ``PositiveOrZero`` constraint was introduced in Symfony 4.3. -Validates that a value is a positive number or equal to zero. To force that -a value is only a positiven umber, see :doc:`/reference/constraints/Positive`. -To force a value is negative or equal to zero, -see :doc:`/reference/constraints/NegativeOrZero`. +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. ========== =================================================================== Applies to :ref:`property or method ` @@ -22,9 +20,8 @@ Validator :class:`Symfony\\Component\\Validator\\Constraints\\GreaterThanOrEqu Basic Usage ----------- -The following constraint ensure that: - -* the number of ``siblings`` of a ``Person`` is positive or zero +The following constraint ensures that the number of ``siblings`` of a ``Person`` +is positive or zero: .. configuration-block:: From 49daee7b841c4e2d4226630131b75f0eb6048073 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 2 Apr 2019 17:39:04 +0200 Subject: [PATCH 067/499] Documented the Mime component --- components/mailer.rst | 25 ++ components/mime.rst | 647 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 672 insertions(+) create mode 100644 components/mailer.rst create mode 100644 components/mime.rst diff --git a/components/mailer.rst b/components/mailer.rst new file mode 100644 index 00000000000..84b31446f09 --- /dev/null +++ b/components/mailer.rst @@ -0,0 +1,25 @@ +.. index:: + single: Mailer + single: Components; Mailer + +The Mailer Component +==================== + + The Mailer component helps sending emails. + +Installation +------------ + +.. code-block:: terminal + + $ composer require symfony/mailer + +Alternatively, you can clone the ``_ repository. + +.. include:: /components/require_autoload.rst.inc + +Usage +----- + +We're currently working on the documentation of this component that was just +added to Symfony. We'll publish it in a few days. diff --git a/components/mime.rst b/components/mime.rst new file mode 100644 index 00000000000..a2a49013f4a --- /dev/null +++ b/components/mime.rst @@ -0,0 +1,647 @@ +.. index:: + single: MIME + single: MIME Messages + single: Components; MIME + +The Mime Component +================== + + The MIME component allows manipulating the MIME messages used to send emails + and provides utilities related to MIME types. + +Installation +------------ + +.. code-block:: terminal + + $ composer require symfony/mime + +Alternatively, you can clone the ``_ repository. + +.. include:: /components/require_autoload.rst.inc + +Introduction +------------ + +`MIME`_ (Multipurpose Internet Mail Extensions) is an Internet standard that +extends the original basic format of emails to support features like: + +* Headers and text contents using non-ASCII characters; +* Message bodies with multiple parts (e.g. HTML and plain text contents); +* Non-text attachments: audio, video, images, PDF, etc. + +The entire MIME standard is complex and huge, but Symfony abstracts all that +complexity to provide two ways of creating MIME messages: + +* A high-level API based on the :class:`Symfony\\Component\\Mime\\Email` class + to quickly create email messages with all the common features; +* A low-level API based on the :class:`Symfony\\Component\\Mime\\Message` class + to have an absolute control over every single part of the email message. + +Usage +----- + +Use the :class:`Symfony\\Component\\Mime\\Email` class and their *chainable* +methods to compose the entire email message:: + + use Symfony\Component\Mime\Email; + + $email = (new Email()) + ->from('fabien@symfony.com') + ->to('foo@example.com') + ->cc('bar@example.com') + ->bcc('baz@example.com') + ->replyTo('fabien@symfony.com') + ->priority(1) + ->subject('Important Notification') + ->text('Lorem ipsum...') + ->html('

Lorem ipsum

...

') + ; + +This only purpose of this component is to create the email messages. Use the +:doc:`Mailer component ` to actually send them. In Symfony +applications, it's easier to use the :doc:`Mailer integration `. + +Email Addresses +--------------- + +All the methods that require email addresses (``from()``, ``to()``, etc.) accept +both strings and objects:: + + // ... + use Symfony\Component\Mime\Address; + use Symfony\Component\Mime\NamedAddress; + + $email = (new Email()) + // email address as a simple string + ->from('fabien@symfony.com') + + // email address as an object + ->from(new Address('fabien@symfony.com')) + + // email address as an object (email clients will display the name + // instead of the email address) + ->from(new NamedAddress('fabien@symfony.com', 'Fabien')) + + // ... + ; + +Multiple addresses are defined with the ``addXXX()`` methods:: + + $email = (new Email()) + ->to('foo@example.com') + ->addTo('bar@example.com') + ->addTo('baz@example.com') + + // ... + ; + +Alternatively, you can pass multiple addresses to each method:: + + $toAddresses = ['foo@example.com', new Address('bar@example.com')]; + + $email = (new Email()) + ->to(...$toAddresses) + ->cc('cc1@example.com', 'cc2@example.com') + + // ... + ; + +Message Contents +---------------- + +The text and HTML contents of the email messages can be strings (usually the +result of rendering some template) or PHP resources:: + + $email = (new Email()) + // ... + // simple contents defined as a string + ->text('Lorem ipsum...') + ->html('

Lorem ipsum...

') + + // contents obtained from a PHP resource + ->text(fopen('/path/to/emails/user_signup.txt', 'r')) + ->html(fopen('/path/to/emails/user_signup.html', 'r')) + ; + +.. tip:: + + You can also use Twig templates to render the HTML and text contents. Read + the :ref:`mime-component-twig-integration` section later in this article to + learn more. + +Embedding Images +---------------- + +If you want to display images inside your email contents, you must embed them +instead of adding them as attachments. When using Twig to render the email +contents, as explained :ref:`later in this article ` +the images are embedded automatically. Otherwise, you need to embed them manually. + +First, use the ``embed()`` or ``embedFromPath()`` method to add an image from a +file or resource:: + + $email = (new Email()) + // ... + // get the image contents from a PHP resource + ->embed(fopen('/path/to/images/logo.png', 'r'), 'logo') + // get the image contents from an existing file + ->embedFromPath('/path/to/images/signature.gif', 'footer-signature') + ; + +The second optional argument of both methods is the image name ("Content-ID" in +the MIME standard). Its value is an arbitrary string used later to reference the +images inside the HTML contents:: + + $email = (new Email()) + // ... + ->embed(fopen('/path/to/images/logo.png', 'r'), 'logo') + ->embedFromPath('/path/to/images/signature.gif', 'footer-signature') + // reference images using the syntax 'cid:' + "image embed name" + ->html(' ... ...') + ; + +File Attachments +---------------- + +Use the ``attachFromPath()`` method to attach files that exist in your file system:: + + $email = (new Email()) + // ... + ->attachFromPath('/path/to/documents/terms-of-use.pdf') + // optionally you can tell email clients to display a custom name for the file + ->attachFromPath('/path/to/documents/privacy.pdf', 'Privacy Policy') + // optionally you can provide an explicit MIME type (otherwise it's guessed) + ->attachFromPath('/path/to/documents/contract.doc', 'Contract', 'application/msword') + ; + +Alternatively you can use the ``attach()`` method to attach contents generated +with PHP resources:: + + $email = (new Email()) + // ... + ->attach(fopen('/path/to/documents/contract.doc', 'r')) + ; + +Creating Raw Email Messages +--------------------------- + +This is useful for advanced applications that need absolute control over every +email part. It's not recommended for applications with regular email +requirements because it adds complexity for no real gain. + +Before continuing, it's important to have a look at the low level structure of +an email message. Consider a message which includes some content as both text +and HTML, a single PNG image embedded in those contents and a PDF file attached +to it. The MIME standard allows structuring this message in different ways, but +the following tree is the one that works on most email clients: + +.. code-block:: text + + multipart/mixed + ├── multipart/related + │   ├── multipart/alternative + │   │   ├── text/plain + │   │   └── text/html + │   └── image/png + └── application/pdf + +This is the purpose of each MIME message part: + +* ``multipart/alternative``: used when two or more parts are alternatives of the + same (or very similar) content. The preferred format must be added last. +* ``multipart/mixed``: used to send different content types in the same message, + such as when attaching files. +* ``multipart/related``: used to indicate that each message part is a component + of an aggregate whole. The most common usage is to display images embedded + in the message contents. + +When using the low-level :class:`Symfony\\Component\\Mime\\Message` class to +create the email message, you must keep all the above in mind to define the +different parts of the email by hand:: + + use Symfony\Component\Mime\Header\Headers; + use Symfony\Component\Mime\Message; + use Symfony\Component\Mime\Part\Multipart\AlternativePart; + use Symfony\Component\Mime\Part\TextPart; + + $headers = (new Headers()) + ->addMailboxListHeader('From', ['fabien@symfony.com']) + ->addMailboxListHeader('To', ['foo@example.com']) + ->addTextHeader('Subject', 'Important Notification') + ; + + $textContent = new TextPart('Lorem ipsum...'); + $htmlContent = new TextPart('

Lorem ipsum

...

', 'html'); + $body = new AlternativePart($textContent, $htmlContent); + + $email = new Message($headers, $body); + +Embedding images and attaching files is possible by creating the appropriate +email multiparts:: + + // ... + use Symfony\Component\Mime\Part\DataPart; + use Symfony\Component\Mime\Part\Multipart\MixedPart; + use Symfony\Component\Mime\Part\Multipart\RelatedPart; + + // ... + $embeddedImage = new DataPart(fopen('/path/to/images/logo.png', 'r'), null, 'image/png'); + $imageCid = $embeddedImage->getContentId(); + + $attachedFile = new DataPart(fopen('/path/to/documents/terms-of-use.pdf', 'r'), null, 'application/pdf'); + + $textContent = new TextPart('Lorem ipsum...'); + $htmlContent = new TextPart(sprintf( + '

Lorem ipsum

...

', $imageCid + ), 'html'); + $bodyContent = new AlternativePart($textContent, $htmlContent); + $body = new RelatedPart($bodyContent, $embeddedImage); + + $messageParts = new MixedPart($body, $attachedFile); + + $email = new Message($headers, $messageParts); + +Serializing Email Messages +-------------------------- + +Email messages created with either the ``Email`` or ``Message`` classes can be +serialized because they are simple data objects:: + + $email = (new Email()) + ->from('fabien@symfony.com') + // ... + ; + + $serializedEmail = serialize($email); + +A common use case is to store serialized email messages, include them in a +message sent with the :doc:`Messenger component ` and +recreate them later when sending them. Use the +:class:`Symfony\\Component\\Mime\\RawMessage` class to recreate email messages +from their serialized contents:: + + use Symfony\Component\Mime\RawMessage; + + // ... + $serializedEmail = serialize($email); + + // later, recreate the original message to actually send it + $message = new RawMessage(unserialize($serializedEmail)); + +.. _mime-component-twig-integration: + +Twig Integration +---------------- + +The Mime component integrates with the :doc:`Twig template engine ` +to provide advanced features such as CSS style inlining and support for HTML/CSS +frameworks to create complex HTML email messages. + +Rendering Email Contents with Twig +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you define the contents of your email in Twig templates, use the +:class:`Symfony\\Bridge\\Twig\\Mime\\TemplatedEmail` class. This class extends +from the :class:`Symfony\\Component\\Mime\\Email` class explained above and adds +some utility methods for Twig templates:: + + use Symfony\Bridge\Twig\Mime\TemplatedEmail; + + $email = (new TemplatedEmail()) + ->from('fabien@symfony.com') + ->fo('foo@example.com') + // ... + + // this method defines the path of the Twig template to render + ->htmlTemplate('messages/user/signup.html.twig') + + // this method defines the parameters (name => value) passed to templates + ->context([ + 'expiration_date' => new \DateTime('+7 days'), + 'username' => 'foo', + ]) + ; + +Once the email object has been created, you must set up Twig to define where +templates are located and then, use the +:class:`Symfony\\Bridge\\Twig\\Mime\\BodyRenderer` class to render the template +and update the email message contents with the results. All this is done +automatically when using the component inside a Symfony application:: + + // ... + use Symfony\Bridge\Twig\Mime\BodyRenderer; + use Twig\Environment; + use Twig\Loader\FilesystemLoader; + + // when using the Mime component inside a full-stack Symfony application, you + // don't need to do this Twig setup. You only have to inject the 'twig' service + $loader = new FilesystemLoader(__DIR__.'/templates'); + $twig = new Environment($loader); + + $renderer = new BodyRenderer($twig); + // this updates the $email object contents with the result of rendering + // the template defined earlier with the given context + $renderer->render($email); + +The last step is to create the Twig template used to render the contents: + +.. code-block:: html+twig + +

Welcome {{ username }}!

+ +

You signed up to our site using the following email:

+

{{ email.to }}

+ +

Click here to activate your account

+ +The Twig template has access to any of the parameters passed in the ``context`` +method of the ``TemplatedEmail`` class and also to a special variable called +``email``. This variable is an instance of the +:class:`Symfony\\Bridge\\Twig\\Mime\\WrappedTemplatedEmail` class which gives +access to some of the email message properties. + +When the text content of the message is not defined explicitly, the +``BodyRenderer()`` class generates it automatically converting the HTML contents +into text. If you have `league/html-to-markdown`_ installed in your application, +it uses that to turn HTML into Markdown. Otherwise, it applies the +:phpfunction:`strip_tags` PHP function to the original HTML contents. + +If you prefer to define the text content yourself, use the ``text()`` method +explained in the previous sections or the ``textTemplate()`` method provided by +the ``TemplatedEmail`` class:: + + use Symfony\Bridge\Twig\Mime\TemplatedEmail; + + $email = (new TemplatedEmail()) + ->from('fabien@symfony.com') + ->fo('foo@example.com') + // ... + + ->textTemplate('messages/user/signup.txt.twig') + ->htmlTemplate('messages/user/signup.html.twig') + + ->context([ + 'expiration_date' => new \DateTime('+7 days'), + 'username' => 'foo', + ]) + ; + +.. _embedding-images-in-emails-with-twig: + +Embedding Images in Emails with Twig +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Instead of dealing with the ```` syntax explained in the +previous sections, when using Twig to render email contents you can refer to +image files as usual. First, define a Twig namespace called ``images`` to +simplify things later:: + + // ... + + $templateLoader = new FilesystemLoader(__DIR__.'/templates'); + $templatedLoader->addPath(__DIR__.'/images', 'images'); + $twig = new Environment($templateLoader); + +Now, use the special ``email.image()`` Twig helper to embed the images inside +the email contents: + +.. code-block:: html+twig + + {# '@images/' refers to the Twig namespace defined earlier #} + + +

Welcome {{ username }}!

+ {# ... #} + +Inlining CSS Styles in Emails with Twig +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Designing the HTML contents of an email is very different from designing a +normal HTML page. For starters, most email clients only support a subset of all +CSS features. In addition, popular email clients such as Gmail don't support +defining styles inside ```` sections and you must **inline +all the CSS styles**. + +CSS inlining means that every HTML tag must define a ``style`` attribute with +all its CSS styles. This not only increases the email byte size significantly +but also makes it impossible to manage for complex emails. That's why Twig +provides a ``CssInlinerExtension`` that automates everything for you. First, +install the Twig extension in your application: + +.. code-block:: terminal + + $ composer require twig/cssinliner-extension + +Now, enable the extension (this is done automatically in Symfony applications):: + + // ... + use Twig\CssInliner\CssInlinerExtension; + + $loader = new FilesystemLoader(__DIR__.'/templates'); + $twig = new Environment($loader); + $twig->addExtension(new CssInlinerExtension()); + +Finally, wrap the entire template contents with the ``inline_css`` filter: + +.. code-block:: html+twig + + {% filter inline_css %} + + +

Welcome {{ username }}!

+ {# ... #} + {% endfilter %} + +You can also define some or all CSS styles in external files and pass them as +arguments of the filter: + +.. code-block:: html+twig + + {# '@css/' refers to the Twig namespace defined earlier #} + {% filter inline_css('@css/mailing.css') %} + + +

Welcome {{ username }}!

+ {# ... #} + {% endfilter %} + +Rendering Markdown Contents in Emails with Twig +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Twig provides another extension called ``MarkdownExtension`` that lets you +define the email contents using the `Markdown syntax`_. In addition to the +extension, you must also install a Markdown conversion library (the extension is +compatible with all the popular libraries): + +.. code-block:: terminal + + $ composer require twig/markdown-extension + + # these libraries are compatible too: erusev/parsedown, michelf/php-markdown + $ composer require league/commonmark + +Now, enable the extension (this is done automatically in Symfony applications):: + + // ... + use Twig\Markdown\MarkdownExtension; + + $loader = new FilesystemLoader(__DIR__.'/templates'); + $twig = new Environment($loader); + $twig->addExtension(new MarkdownExtension()); + +Finally, use the ``markdown`` filter to convert parts or the entire email +contents from Markdown to HTML: + +.. code-block:: html+twig + + {% filter markdown %} + Welcome {{ username }}! + ======================= + + You signed up to our site using the following email: + `{{ email.to }}` + + [Click here to activate your account]({{ url('...') }}) + {% endfilter %} + +Using the Inky Email Templating Language with Twig +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Creating beautifully designed emails that work on every email client is so +complex that there are HTML/CSS frameworks dedicated to that. One of the most +popular frameworks is called `Inky`_. It defines a syntax based on some simple +tags which are later transformed into the real HTML code sent to users: + +.. code-block:: html + + + + + This is a column. + + + +Twig provides integration with Inky via the ``InkyExtension``. First, install +the extension in your application: + +.. code-block:: terminal + + $ composer require twig/inky-extension + +Now, enable the extension (this is done automatically in Symfony applications):: + + // ... + use Twig\Inky\InkyExtension; + + $loader = new FilesystemLoader(__DIR__.'/templates'); + $twig = new Environment($loader); + $twig->addExtension(new InkyExtension()); + +Finally, use the ``inky`` filter to convert parts or the entire email +contents from Inky to HTML: + +.. code-block:: html+twig + + {% filter inky %} + + + + +

Welcome {{ username }}!

+
+ + {# ... #} +
+
+ {% endfilter %} + +You can combine all filters to create complex email messages: + +.. code-block:: html+twig + + {% filter inky|inline_css(source('@zurb/stylesheets/main.css')) %} + {# ... #} + {% endfilter %} + +MIME Types Utilities +-------------------- + +Although MIME was designed mainly for creating emails, the content types (also +known as `MIME types`_ and "media types") defined by MIME standards are also of +importance in communication protocols outside of email, such as HTTP. That's +why this component also provides utilities to work with MIME types. + +The :class:`Symfony\\Component\\Mime\\MimeTypes` class transforms between +MIME types and file name extensions:: + + use Symfony\Component\Mime\MimeTypes; + + $mimeTypes = new MimeTypes(); + $exts = $mimeTypes->getExtensions('application/javascript'); + // $exts = ['js', 'jsm', 'mjs'] + $exts = $mimeTypes->getExtensions('image/jpeg'); + // $exts = ['jpeg', 'jpg', 'jpe'] + + $mimeTypes = $mimeTypes->getMimeTypes('js'); + // $mimeTypes = ['application/javascript', 'application/x-javascript', 'text/javascript'] + $mimeTypes = $mimeTypes->getMimeTypes('apk'); + // $mimeTypes = ['application/vnd.android.package-archive'] + +These methods return arrays with one or more elements. The element position +indicates its priority, so the first returned extension is the preferred one. + +Guessing the MIME Type +~~~~~~~~~~~~~~~~~~~~~~ + +Another useful utility allows to guess the MIME type of any given file:: + + use Symfony\Component\Mime\MimeTypes; + + $mimeTypes = new MimeTypes(); + $mimeType = $mimeTypes->guessMimeType('/some/path/to/image.gif'); + // Guessing is not based on the file name, so $mimeType will be 'image/gif' + // only if the given file is truly a GIF image + +Guessing the MIME type is a time-consuming process that requires inspecting +part of the file contents. Symfony applies multiple guessing mechanisms, one +of them based on the PHP `fileinfo extension`_. It's recommended to install +that extension to improve the guessing performance. + +Adding a MIME Type Guesser +.......................... + +You can register your own MIME type guesser by creating a class that implements +:class:`Symfony\\Component\\Mime\\MimeTypeGuesserInterface`:: + + namespace App; + + use Symfony\Component\Mime\MimeTypeGuesserInterface; + + class SomeMimeTypeGuesser implements MimeTypeGuesserInterface + { + public function isGuesserSupported(): bool + { + // return true when the guesser is supported (might depend on the OS for instance) + return true; + } + + public function guessMimeType(string $path): ?string + { + // inspect the contents of the file stored in $path to guess its + // type and return a valid MIME type ... or null if unknown + + return '...'; + } + } + +.. _`MIME`: https://en.wikipedia.org/wiki/MIME +.. _`league/html-to-markdown`: https://github.com/thephpleague/html-to-markdown +.. _`Markdown syntax`: https://commonmark.org/ +.. _`Inky`: https://foundation.zurb.com/emails.html +.. _`MIME types`: https://en.wikipedia.org/wiki/Media_type +.. _`fileinfo extension`: https://php.net/fileinfo From 6954e8d2624797d12e1ff83fb68bd184dc561405 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Apr 2019 15:59:03 +0200 Subject: [PATCH 068/499] Tweaks --- components/dom_crawler.rst | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index 2f5298988e4..c223266d9d0 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -74,10 +74,13 @@ tree. .. note:: - When available, the DomCrawler will use the - [html5-php library](https://github.com/Masterminds/html5-php) to parse HTML content. - If you need to support specific HTML5 tags ou if you are getting unexpected behaviors - using the DomCrawler, you can install the library to fix the problem. + If you need better support for HTML5 contents or want to get rid of the + inconsistencies of PHP's DOM extension, install the `html5-php library`_. + The DomCrawler component uses it automatically when available. + + .. versionadded:: 4.3 + + The automatic support of the html5-php library was introduced in Symfony 4.3. Node Filtering ~~~~~~~~~~~~~~ @@ -580,11 +583,12 @@ the whole form or specific field(s):: $form->disableValidation(); $form['country']->select('Invalid value'); -.. _`Goutte`: https://github.com/FriendsOfPHP/Goutte -.. _Packagist: https://packagist.org/packages/symfony/dom-crawler - Learn more ---------- * :doc:`/testing` * :doc:`/components/css_selector` + +.. _`Goutte`: https://github.com/FriendsOfPHP/Goutte +.. _Packagist: https://packagist.org/packages/symfony/dom-crawler +.. _`html5-php library`: https://github.com/Masterminds/html5-php From 1b15af7660dd47e12e6d165a6daf386a7cfc2165 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Apr 2019 16:15:08 +0200 Subject: [PATCH 069/499] Tweaks --- service_container/configurators.rst | 39 ++++++++++++++--------------- service_container/factories.rst | 29 ++++++++++----------- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/service_container/configurators.rst b/service_container/configurators.rst index 666d78c625b..fcde444f8d6 100644 --- a/service_container/configurators.rst +++ b/service_container/configurators.rst @@ -203,30 +203,29 @@ the service id and the method name: Services can be configured via invokable configurators (replacing the ``configure()`` method with ``__invoke()``) by omitting the method name, just as -route definitions can reference :ref:`invokable -controllers `. +routes can reference :ref:`invokable controllers `. .. code-block:: yaml - # app/config/services.yml + # config/services.yaml services: # ... - # Registers all 4 classes as services, including AppBundle\Mail\EmailConfigurator - AppBundle\: - resource: '../../src/AppBundle/*' + # registers all classes as services, including App\Mail\EmailConfigurator + App\: + resource: '../src/*' # ... # override the services to set the configurator - AppBundle\Mail\NewsletterManager: - configurator: '@AppBundle\Mail\EmailConfigurator' + App\Mail\NewsletterManager: + configurator: '@App\Mail\EmailConfigurator' - AppBundle\Mail\GreetingCardManager: - configurator: '@AppBundle\Mail\EmailConfigurator' + App\Mail\GreetingCardManager: + configurator: '@App\Mail\EmailConfigurator' .. code-block:: xml - + `. http://symfony.com/schema/dic/services/services-1.0.xsd"> - + - - + + - - + + .. code-block:: php - // app/config/services.php - use AppBundle\Mail\GreetingCardManager; - use AppBundle\Mail\NewsletterManager; + // config/services.php + use App\Mail\GreetingCardManager; + use App\Mail\NewsletterManager; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; @@ -259,7 +258,7 @@ controllers `. $definition->setAutowired(true); - $this->registerClasses($definition, 'AppBundle\\', '../../src/AppBundle/*'); + $this->registerClasses($definition, 'App\\', '../src/*'); $container->getDefinition(NewsletterManager::class) ->setConfigurator(new Reference(EmailConfigurator::class)); diff --git a/service_container/factories.rst b/service_container/factories.rst index 725915f6060..e121f43aea9 100644 --- a/service_container/factories.rst +++ b/service_container/factories.rst @@ -180,26 +180,24 @@ factory service can be used as a callback:: 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 route definitions can reference :ref:`invokable -controllers `. +method name, just as routes can reference +:ref:`invokable controllers `. .. configuration-block:: .. code-block:: yaml - # app/config/services.yml - + # config/services.yaml services: # ... - AppBundle\Email\NewsletterManager: - class: AppBundle\Email\NewsletterManager - factory: '@AppBundle\Email\NewsletterManagerFactory' + App\Email\NewsletterManager: + class: App\Email\NewsletterManager + factory: '@App\Email\NewsletterManagerFactory' .. code-block:: xml - - + `. - - + + .. code-block:: php - // app/config/services.php - - use AppBundle\Email\NewsletterManager; - use AppBundle\Email\NewsletterManagerFactory; + // config/services.php + use App\Email\NewsletterManager; + use App\Email\NewsletterManagerFactory; use Symfony\Component\DependencyInjection\Reference; // ... From bcd6a4860b5fe6f87349be795aeadd8b8d16f0c2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Apr 2019 17:52:16 +0200 Subject: [PATCH 070/499] Tweaks --- components/options_resolver.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/options_resolver.rst b/components/options_resolver.rst index 3d1286d3b35..a984b456101 100644 --- a/components/options_resolver.rst +++ b/components/options_resolver.rst @@ -435,13 +435,15 @@ if you need to use other options during normalization:: } } +To normalize a new allowed value in sub-classes that are being normalized +in parent classes use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::addNormalizer`. +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 - To normalize a new allowed value in sub-classes that is being normalized - in parent classes use :method:`Symfony\\Component\\OptionsResolver\\OptionsResolver::addNormalizer`. - This way, the ``$value`` argument will receive the previously normalized - value, otherwise you can prepend the new normalizer by passing ``true`` as - third argument. + The ``addNormalizer()`` method was introduced in Symfony 4.3. Default Values that Depend on another Option ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 33ecc96790560b8d2867b03e9d6c2c93106a7cab Mon Sep 17 00:00:00 2001 From: Denis Brumann Date: Sat, 6 Apr 2019 13:55:18 +0200 Subject: [PATCH 071/499] Remove references to github repositories. Fixes #11295 for #EUFOSSA See also PRs #11307 for 4.2 and #11306 for 3.4 for remaining references. --- components/mailer.rst | 2 -- components/mime.rst | 2 -- 2 files changed, 4 deletions(-) diff --git a/components/mailer.rst b/components/mailer.rst index 84b31446f09..b36b44efb3d 100644 --- a/components/mailer.rst +++ b/components/mailer.rst @@ -14,8 +14,6 @@ Installation $ composer require symfony/mailer -Alternatively, you can clone the ``_ repository. - .. include:: /components/require_autoload.rst.inc Usage diff --git a/components/mime.rst b/components/mime.rst index a2a49013f4a..00b91368fbb 100644 --- a/components/mime.rst +++ b/components/mime.rst @@ -16,8 +16,6 @@ Installation $ composer require symfony/mime -Alternatively, you can clone the ``_ repository. - .. include:: /components/require_autoload.rst.inc Introduction From b733aea2598358cf27189d5fdebc02e11b11ec8d Mon Sep 17 00:00:00 2001 From: Denis Brumann Date: Sat, 6 Apr 2019 15:12:45 +0200 Subject: [PATCH 072/499] Adds deprecation for non-string env values. --- configuration/environment_variables.rst | 31 ++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/configuration/environment_variables.rst b/configuration/environment_variables.rst index 50a2bd77daf..c253b96810f 100644 --- a/configuration/environment_variables.rst +++ b/configuration/environment_variables.rst @@ -77,7 +77,7 @@ whenever the corresponding environment variable is *not* found: # config/services.yaml parameters: - env(DATABASE_HOST): localhost + env(DATABASE_HOST): 'localhost' .. code-block:: xml @@ -97,6 +97,35 @@ whenever the corresponding environment variable is *not* found: // config/services.php $container->setParameter('env(DATABASE_HOST)', 'localhost'); +.. deprecated:: 4.3 + + Passing non-string values as default values for environment variables is no longer supported. Any non-string value, + e.g. an integer or float must be passed as string. + + .. code-block:: yaml + + # config/services.yaml + parameters: + env(DATABASE_PORT): '3306' + + .. code-block:: xml + + + + + + + 3306 + + + + .. code-block:: php + + // config/services.php + $container->setParameter('env(DATABASE_PORT)', '3306'); + .. _configuration-env-var-in-prod: Configuring Environment Variables in Production From 77f390b70db68c0ac3a6e301c2c237ad237c8a19 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 6 Apr 2019 15:50:29 +0200 Subject: [PATCH 073/499] Made the deprecation notice more concise --- configuration/environment_variables.rst | 31 ++++--------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/configuration/environment_variables.rst b/configuration/environment_variables.rst index c253b96810f..8ea248cac30 100644 --- a/configuration/environment_variables.rst +++ b/configuration/environment_variables.rst @@ -99,32 +99,9 @@ whenever the corresponding environment variable is *not* found: .. deprecated:: 4.3 - Passing non-string values as default values for environment variables is no longer supported. Any non-string value, - e.g. an integer or float must be passed as string. - - .. code-block:: yaml - - # config/services.yaml - parameters: - env(DATABASE_PORT): '3306' - - .. code-block:: xml - - - - - - - 3306 - - - - .. code-block:: php - - // config/services.php - $container->setParameter('env(DATABASE_PORT)', '3306'); + 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. .. _configuration-env-var-in-prod: @@ -161,6 +138,8 @@ the following: :doc:`Symfony profiler `. In practice this shouldn't be a problem because the web profiler must **never** be enabled in production. +.. _env-var-processors: + Environment Variable Processors ------------------------------- From 78a93870f6584c6a6518de10c2c94101fa0ca9c6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 5 Apr 2019 12:58:07 +0200 Subject: [PATCH 074/499] Added docs for the NotCompromisedPassword constraint --- reference/constraints.rst | 1 + reference/constraints/NotPwned.rst | 133 +++++++++++++++++++++++++++++ reference/constraints/map.rst.inc | 1 + 3 files changed, 135 insertions(+) create mode 100644 reference/constraints/NotPwned.rst diff --git a/reference/constraints.rst b/reference/constraints.rst index 9cbe8bcccf9..142c94f6a4a 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -66,6 +66,7 @@ Validation Constraints Reference constraints/All constraints/UserPassword constraints/Valid + constraints/NotCompromisedPassword 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/NotPwned.rst b/reference/constraints/NotPwned.rst new file mode 100644 index 00000000000..30a43828ed1 --- /dev/null +++ b/reference/constraints/NotPwned.rst @@ -0,0 +1,133 @@ +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 is +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` +========== =================================================================== + +Basic Usage +----------- + +The following constraint ensures that the ``rawPassword`` property of the +``User`` class doesn't store a compromised password: + +.. configuration-block:: + + .. code-block:: php-annotations + + // 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 + App\Entity\User: + properties: + rawPassword: + - NotCompromisedPassword + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/User.php + namespace App\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class User + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('rawPassword', new Assert\NotCompromisedPassword()); + } + } + +In order to make the password validation, this constraint doesn't send the raw +password value to the ``haveibeenpwned.com`` API. Instead, it follows a secure +process known as `k-anonimity password validation`_. + +In practice, the raw password is hashed using SHA-1 and only the first bytes of +the hash are sent. Then, the ``haveibeenpwned.com`` API compares those bytes +with the SHA-1 hashes of all leaked passwords and returns the list of hashes +that start with those same bytes. That's how the constraint can check if the +password has been compromised without fully disclosing it. + +For example, if the password is ``test``, the entire SHA-1 hash is +``a94a8fe5ccb19ba61c4c0873d391e987982fbbd3`` but the validator only sends +``a94a8`` to the ``haveibeenpwned.com`` API. + +Available Options +----------------- + +.. include:: /reference/constraints/_groups-option.rst.inc + +message +~~~~~~~ + +**type**: ``string`` **default**: ``This password has been leaked in a data breach, it must not be used. Please use another password.`` + +The default message supplied when the password has been compromised. + +.. include:: /reference/constraints/_payload-option.rst.inc + +skipOnError +~~~~~~~~~~~ + +**type**: ``boolean`` **default**: ``false`` + +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 +~~~~~~~~~ + +**type**: ``integer`` **default**: ``1`` + +This value defines the number of times a password should have been leaked +publicly to consider it compromised. Think carefully before setting this option +to a higher value because it could decrease the security of your application. + +.. _`haveibeenpwned.com`: https://haveibeenpwned.com/ +.. _`k-anonimity password validation`: https://blog.cloudflare.com/validating-leaked-passwords-with-k-anonymity/ diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index f0a5696648d..7055516d14b 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -88,3 +88,4 @@ Other Constraints * :doc:`Collection ` * :doc:`Count ` * :doc:`UniqueEntity ` +* :doc:`NotCompromisedPassword ` From b0b149882557356a8f8b391640b7fd262a2addf8 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Sat, 6 Apr 2019 16:35:42 +0200 Subject: [PATCH 075/499] [Validator] add documentation for the new `Timezone` constraint. --- reference/constraints.rst | 2 + reference/constraints/Timezone.rst | 127 +++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 reference/constraints/Timezone.rst diff --git a/reference/constraints.rst b/reference/constraints.rst index 9cbe8bcccf9..b0c645cd53b 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -42,6 +42,8 @@ Validation Constraints Reference constraints/DateTime constraints/Time + constraints/Timezone + constraints/Choice constraints/Collection constraints/Count diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst new file mode 100644 index 00000000000..403c5861a6a --- /dev/null +++ b/reference/constraints/Timezone.rst @@ -0,0 +1,127 @@ +Timezone +======== + +Validates that a value is a valid timezone identifier (ie. ``Europe/Paris``). + +========== =================================================================== +Applies to :ref:`property or method ` +Options - `groups`_ + - `message`_ + - `payload`_ +Class :class:`Symfony\\Component\\Validator\\Constraints\\Timezone` +Validator :class:`Symfony\\Component\\Validator\\Constraints\\TimezoneValidator` +========== =================================================================== + +Basic Usage +----------- + +Suppose you have a ``UserSettings`` class, with a ``timezone`` field that is a string +meant to contain a timezone identifier (ie. `America/New_York`): + +.. configuration-block:: + + .. code-block:: php-annotations + + // src/Entity/UserSettings.php + namespace App\Entity; + + use Symfony\Component\Validator\Constraints as Assert; + + class UserSettings + { + /** + * @Assert\Timezone + * @var string A timezone identifier + */ + protected $timezone; + } + + .. code-block:: yaml + + # config/validator/validation.yaml + App\Entity\UserSettings: + properties: + timezone: + - Timezone: ~ + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // src/Entity/UserSettings.php + namespace App\Entity; + + use Symfony\Component\Validator\Mapping\ClassMetadata; + use Symfony\Component\Validator\Constraints as Assert; + + class Event + { + /** + * @var string A timezone identifier + */ + protected $timezone; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('startsAt', new Assert\Timezone()); + } + } + +.. 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 time.`` + +This message is shown if the underlying data is not a valid time. + +You can use the following parameters in this message: + +=============== ============================================================== +Parameter Description +=============== ============================================================== +``{{ value }}`` The current (invalid) value +=============== ============================================================== + +.. include:: /reference/constraints/_payload-option.rst.inc + +zone +~~~~ + +**type**: ``string`` **default**: ``\DateTimeZone::ALL.`` + +The geographical zone in which to validate the timezone identifier. + +Value must be any of the `DateTimeZone`_ class constants values. + +countryCode +~~~~~~~~~~~ + +**type**: ``string`` **default**: ``null`` + +This option must be used only when the ``zone`` option value equals ``\DateTimeZone::PER_COUNTRY``. + +The ``countryCode`` option enables to validate the timezone identifier is supported by the country code. + +Value must be a valid `ISO 3166-1 alpha-2` country code (ie. `BE`). + +.. _DateTimeZone: https://www.php.net/datetimezone From 1c7eb7929e665f5d6f4d06dea359e560d2d37a59 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 6 Apr 2019 16:28:42 +0200 Subject: [PATCH 076/499] Minor improvement in the DomCrawler + HTML5 explanation --- components/dom_crawler.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index cc4491eb517..dffe4d63a5e 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -74,7 +74,8 @@ tree. If you need better support for HTML5 contents or want to get rid of the inconsistencies of PHP's DOM extension, install the `html5-php library`_. - The DomCrawler component uses it automatically when available. + The DomCrawler component will use it automatically when the content has + an HTML5 doctype. .. versionadded:: 4.3 From 135c5ffed3ccccaaf391a937ba30f451a4af1403 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 6 Apr 2019 16:49:58 +0200 Subject: [PATCH 077/499] Minor fixes --- reference/constraints/Timezone.rst | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 403c5861a6a..2997d343a41 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -1,7 +1,7 @@ Timezone ======== -Validates that a value is a valid timezone identifier (ie. ``Europe/Paris``). +Validates that a value is a valid timezone identifier (e.g. ``Europe/Paris``). ========== =================================================================== Applies to :ref:`property or method ` @@ -15,8 +15,8 @@ Validator :class:`Symfony\\Component\\Validator\\Constraints\\TimezoneValidato Basic Usage ----------- -Suppose you have a ``UserSettings`` class, with a ``timezone`` field that is a string -meant to contain a timezone identifier (ie. `America/New_York`): +Suppose you have a ``UserSettings`` class, with a ``timezone`` field that is a +string meant to contain a timezone identifier (ie. ``America/New_York``): .. configuration-block:: @@ -31,7 +31,6 @@ meant to contain a timezone identifier (ie. `America/New_York`): { /** * @Assert\Timezone - * @var string A timezone identifier */ protected $timezone; } @@ -69,9 +68,6 @@ meant to contain a timezone identifier (ie. `America/New_York`): class Event { - /** - * @var string A timezone identifier - */ protected $timezone; public static function loadValidatorMetadata(ClassMetadata $metadata) @@ -90,9 +86,9 @@ Options message ~~~~~~~ -**type**: ``string`` **default**: ``This value is not a valid time.`` +**type**: ``string`` **default**: ``This value is not a valid timezone.`` -This message is shown if the underlying data is not a valid time. +This message is shown if the underlying data is not a valid timezone identifier. You can use the following parameters in this message: @@ -107,7 +103,7 @@ Parameter Description zone ~~~~ -**type**: ``string`` **default**: ``\DateTimeZone::ALL.`` +**type**: ``string`` **default**: ``\DateTimeZone::ALL`` The geographical zone in which to validate the timezone identifier. @@ -122,6 +118,7 @@ This option must be used only when the ``zone`` option value equals ``\DateTimeZ The ``countryCode`` option enables to validate the timezone identifier is supported by the country code. -Value must be a valid `ISO 3166-1 alpha-2` country code (ie. `BE`). +Value must be a valid `ISO 3166-1 alpha-2`_ country code (e.g. ``BE``). -.. _DateTimeZone: https://www.php.net/datetimezone +.. _`DateTimeZone`: https://www.php.net/datetimezone +.. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 From ac6282fa3633b7c96a92b9d1b20fefbe048f6e64 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 6 Apr 2019 17:02:43 +0200 Subject: [PATCH 078/499] Listed the geographical zones defined by PHP --- reference/constraints/Timezone.rst | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 2997d343a41..995f278acb1 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -105,20 +105,33 @@ zone **type**: ``string`` **default**: ``\DateTimeZone::ALL`` -The geographical zone in which to validate the timezone identifier. - -Value must be any of the `DateTimeZone`_ class constants values. +Set this option to any of the following constants to restrict the valid timezone +identifiers to the ones that belong to that geographical zone: + +* ``\DateTimeZone::AFRICA`` +* ``\DateTimeZone::AMERICA`` +* ``\DateTimeZone::ANTARCTICA`` +* ``\DateTimeZone::ARCTIC`` +* ``\DateTimeZone::ASIA`` +* ``\DateTimeZone::ATLANTIC`` +* ``\DateTimeZone::AUSTRALIA`` +* ``\DateTimeZone::EUROPE`` +* ``\DateTimeZone::INDIAN`` +* ``\DateTimeZone::PACIFIC`` + +The special ``\DateTimeZone::ALL`` zone accepts any timezone. countryCode ~~~~~~~~~~~ **type**: ``string`` **default**: ``null`` -This option must be used only when the ``zone`` option value equals ``\DateTimeZone::PER_COUNTRY``. - -The ``countryCode`` option enables to validate the timezone identifier is supported by the country code. +If the ``zone`` option is set to ``\DateTimeZone::PER_COUNTRY``, this option +restricts the valid timezone identifiers to the ones that belong to the given +country. -Value must be a valid `ISO 3166-1 alpha-2`_ country code (e.g. ``BE``). +The value of this option must be a valid `ISO 3166-1 alpha-2`_ country code +(e.g. ``CN`` for China). .. _`DateTimeZone`: https://www.php.net/datetimezone .. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 From d564218d4811df9a47d91f17063c1248cd5cfdda Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 6 Apr 2019 17:03:36 +0200 Subject: [PATCH 079/499] Minor fixes --- reference/constraints/Timezone.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 995f278acb1..7a0dcb27ffb 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -16,7 +16,7 @@ Basic Usage ----------- Suppose you have a ``UserSettings`` class, with a ``timezone`` field that is a -string meant to contain a timezone identifier (ie. ``America/New_York``): +string meant to contain a timezone identifier (e.g. ``America/New_York``): .. configuration-block:: @@ -72,7 +72,7 @@ string meant to contain a timezone identifier (ie. ``America/New_York``): public static function loadValidatorMetadata(ClassMetadata $metadata) { - $metadata->addPropertyConstraint('startsAt', new Assert\Timezone()); + $metadata->addPropertyConstraint('timezone', new Assert\Timezone()); } } From 4e7035c38dfb4d9257423d4ff957c8c4fa23e097 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 6 Apr 2019 17:05:13 +0200 Subject: [PATCH 080/499] fix document filename --- .../constraints/{NotPwned.rst => NotCompromisedPassword.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename reference/constraints/{NotPwned.rst => NotCompromisedPassword.rst} (100%) diff --git a/reference/constraints/NotPwned.rst b/reference/constraints/NotCompromisedPassword.rst similarity index 100% rename from reference/constraints/NotPwned.rst rename to reference/constraints/NotCompromisedPassword.rst From b37bc7855a54e2dbeeef9e722ade7760d4dab7f3 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Sat, 6 Apr 2019 17:33:57 +0200 Subject: [PATCH 081/499] Minor fixes --- reference/constraints/Timezone.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 7a0dcb27ffb..8e61a9ad3c4 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -3,14 +3,14 @@ Timezone Validates that a value is a valid timezone identifier (e.g. ``Europe/Paris``). -========== =================================================================== +========== ====================================================================== Applies to :ref:`property or method ` Options - `groups`_ - `message`_ - `payload`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Timezone` Validator :class:`Symfony\\Component\\Validator\\Constraints\\TimezoneValidator` -========== =================================================================== +========== ====================================================================== Basic Usage ----------- @@ -66,7 +66,7 @@ string meant to contain a timezone identifier (e.g. ``America/New_York``): use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; - class Event + class UserSettings { protected $timezone; From c5681bf05e0510d2aea1b13b9cc4ff195b55e05e Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Sat, 6 Apr 2019 17:38:56 +0200 Subject: [PATCH 082/499] Add more explanations --- reference/constraints/Timezone.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 8e61a9ad3c4..a782242ef90 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -119,10 +119,15 @@ identifiers to the ones that belong to that geographical zone: * ``\DateTimeZone::INDIAN`` * ``\DateTimeZone::PACIFIC`` -The special ``\DateTimeZone::ALL`` zone accepts any timezone. +The special ``\DateTimeZone::ALL`` zone accepts any timezone excluding deprecated timezones. -countryCode -~~~~~~~~~~~ +The special ``\DateTimeZone::ALL_WITH_BC`` zone accepts any timezone including deprecated timezones. + +The special ``\DateTimeZone::PER_COUNTRY`` zone limits the timezones to a certain country. This zone +value must be used in combination with the ``country_code`` option. + +country_code +~~~~~~~~~~~~ **type**: ``string`` **default**: ``null`` From 9cbeb75f5763420160044e8e8b0de4d93d551050 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Sat, 6 Apr 2019 17:40:51 +0200 Subject: [PATCH 083/499] Fixes options list table --- reference/constraints/Timezone.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index a782242ef90..0ffa8c5740f 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -8,6 +8,8 @@ Applies to :ref:`property or method ` Options - `groups`_ - `message`_ - `payload`_ + - `zone`_ + - `country_code`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Timezone` Validator :class:`Symfony\\Component\\Validator\\Constraints\\TimezoneValidator` ========== ====================================================================== From ec7bd4065b5a884014e681f296a7a64e9b16969a Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Sat, 6 Apr 2019 17:43:51 +0200 Subject: [PATCH 084/499] Revert country_code to countryCode --- reference/constraints/Timezone.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 0ffa8c5740f..8e237346404 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -9,7 +9,7 @@ Options - `groups`_ - `message`_ - `payload`_ - `zone`_ - - `country_code`_ + - `countryCode`_ Class :class:`Symfony\\Component\\Validator\\Constraints\\Timezone` Validator :class:`Symfony\\Component\\Validator\\Constraints\\TimezoneValidator` ========== ====================================================================== @@ -128,8 +128,8 @@ The special ``\DateTimeZone::ALL_WITH_BC`` zone accepts any timezone including d The special ``\DateTimeZone::PER_COUNTRY`` zone limits the timezones to a certain country. This zone value must be used in combination with the ``country_code`` option. -country_code -~~~~~~~~~~~~ +countryCode +~~~~~~~~~~~ **type**: ``string`` **default**: ``null`` From 98dfd5d3db5f199def30e34abc40ebc7009d13c5 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Sat, 6 Apr 2019 17:43:57 +0200 Subject: [PATCH 085/499] [#11156] Added versionadded and slightly reordered the code example --- components/property_access.rst | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/components/property_access.rst b/components/property_access.rst index 44346468806..e0b13a6dca8 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -166,19 +166,21 @@ getters, this means that you can do something like this:: This will produce: ``He is an author`` -Accessing a non existing property path +Accessing a non Existing Property Path ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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 behaviour using the :method:`Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder::disableExceptionOnInvalidPropertyPath` +.. 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 behaviour using the +:method:`Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder::disableExceptionOnInvalidPropertyPath` method:: // ... - $propertyAccessor = PropertyAccess::createPropertyAccessorBuilder() - ->disableExceptionOnInvalidPropertyPath() - ->getPropertyAccessor(); - class Person { public $name; @@ -186,6 +188,10 @@ method:: $person = new Person(); + $propertyAccessor = PropertyAccess::createPropertyAccessorBuilder() + ->disableExceptionOnInvalidPropertyPath() + ->getPropertyAccessor(); + // instead of throwing an exception the following code returns null $value = $propertyAccessor->getValue($person, 'birthday'); From 5ec9159cd32a19c329bad7de07cee7d9b019ed44 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Sat, 6 Apr 2019 17:49:54 +0200 Subject: [PATCH 086/499] Fix option --- reference/constraints/Timezone.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 8e237346404..cbbf9eb3c72 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -126,7 +126,7 @@ The special ``\DateTimeZone::ALL`` zone accepts any timezone excluding deprecate The special ``\DateTimeZone::ALL_WITH_BC`` zone accepts any timezone including deprecated timezones. The special ``\DateTimeZone::PER_COUNTRY`` zone limits the timezones to a certain country. This zone -value must be used in combination with the ``country_code`` option. +value must be used in combination with the ``countryCode`` option. countryCode ~~~~~~~~~~~ From 8e33d4721e32e56955b3499e7e13c28b007a891b Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Sat, 6 Apr 2019 17:57:05 +0200 Subject: [PATCH 087/499] Fixes classification --- reference/constraints.rst | 3 +-- reference/constraints/map.rst.inc | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/constraints.rst b/reference/constraints.rst index b0c645cd53b..7eb0b3a5ad8 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -42,8 +42,6 @@ Validation Constraints Reference constraints/DateTime constraints/Time - constraints/Timezone - constraints/Choice constraints/Collection constraints/Count @@ -51,6 +49,7 @@ Validation Constraints Reference constraints/Language constraints/Locale constraints/Country + constraints/Timezone constraints/File constraints/Image diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index f0a5696648d..adbc55017c6 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -60,6 +60,7 @@ Choice Constraints * :doc:`Language ` * :doc:`Locale ` * :doc:`Country ` +* :doc:`Timezone ` File Constraints ~~~~~~~~~~~~~~~~ From ecede2dd1435cdccd40addd1285cffc653abb8e9 Mon Sep 17 00:00:00 2001 From: Neal Brooks Date: Sat, 6 Apr 2019 18:04:11 +0100 Subject: [PATCH 088/499] fix typo `spaccer` => `spacer` --- components/mime.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mime.rst b/components/mime.rst index 00b91368fbb..34b06cd40de 100644 --- a/components/mime.rst +++ b/components/mime.rst @@ -549,7 +549,7 @@ contents from Inky to HTML: - +

Welcome {{ username }}!

From c004dc54e311264b8400bba254bc3eb4b7118c0a Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 6 Apr 2019 16:00:24 +0200 Subject: [PATCH 089/499] document the input option of the NumberType --- reference/forms/types/number.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/reference/forms/types/number.rst b/reference/forms/types/number.rst index 3fad6c65e52..c5db2c7b092 100644 --- a/reference/forms/types/number.rst +++ b/reference/forms/types/number.rst @@ -13,6 +13,7 @@ that you want to use for your number. +-------------+----------------------------------------------------------------------+ | Options | - `grouping`_ | | | - `html5`_ | +| | - `input`_ | | | - `scale`_ | | | - `rounding_mode`_ | +-------------+----------------------------------------------------------------------+ @@ -59,6 +60,21 @@ html5 If set to ``true``, the HTML input will be rendered as a native HTML5 ``type="number"`` form. +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 +for precision reasons (for example, Doctrine uses strings for the ``decimal`` +type). + scale ~~~~~ From 0cba12ea6e3636ede738d588faf9f7b6b627743e Mon Sep 17 00:00:00 2001 From: Wouter J Date: Sun, 7 Apr 2019 10:42:15 +0200 Subject: [PATCH 090/499] [#11317] Added versionadded --- reference/constraints/Timezone.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index cbbf9eb3c72..c06f4ae92d6 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -1,6 +1,10 @@ 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``). ========== ====================================================================== From 3b1a1a13277e89cf8f16b58ad1fe0eab22982b3b Mon Sep 17 00:00:00 2001 From: Alex Rock Ancelet Date: Tue, 2 Apr 2019 20:50:37 +0200 Subject: [PATCH 091/499] Add docs of new WebTestCase assertions --- testing.rst | 27 ++++++-- testing/functional_tests_assertions.rst | 83 +++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 testing/functional_tests_assertions.rst diff --git a/testing.rst b/testing.rst index d92d71a463b..d1844bed94d 100644 --- a/testing.rst +++ b/testing.rst @@ -204,12 +204,29 @@ component, run: $ composer require --dev symfony/css-selector Now you can use CSS selectors with the crawler. To assert that the phrase -"Hello World" is on the page at least once, you can use this assertion:: +"Hello World" is present in the page's main title, you can use this assertion:: - $this->assertGreaterThan( - 0, - $crawler->filter('html:contains("Hello World")')->count() - ); + $this->assertSelectorTextContains('html h1.title', 'Hello World'); + +This assertion will internally call ``$crawler->filter('html h1.title')``, which allows +you to use CSS selectors to filter any HTML element in the page and check for +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:: + + $this->assertGreaterThan( + 0, + $crawler->filter('html h1.title:contains("Hello World")')->count() + ); 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, diff --git a/testing/functional_tests_assertions.rst b/testing/functional_tests_assertions.rst new file mode 100644 index 00000000000..63482dd046b --- /dev/null +++ b/testing/functional_tests_assertions.rst @@ -0,0 +1,83 @@ +.. index:: + single: Tests; Assertions + +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. + +Here is an example with plain PHPUnit:: + + $this->assertGreaterThan( + 0, + $crawler->filter('html:contains("Hello World")')->count() + ); + +Now here is the example with the assertions specific to Symfony:: + + $this->assertSelectorTextContains('html', 'Hello World'); + +.. note:: + + These assertions only work if a request has been made with the ``Client`` + in a test case extending the ``WebTestCase`` class. + +Assertions Reference +--------------------- + +Response +~~~~~~~~ + +- ``assertResponseIsSuccessful()`` +- ``assertResponseStatusCodeSame()`` +- ``assertResponseRedirects()`` +- ``assertResponseHasHeader()`` +- ``assertResponseNotHasHeader()`` +- ``assertResponseHeaderSame()`` +- ``assertResponseHeaderNotSame()`` +- ``assertResponseHasCookie()`` +- ``assertResponseNotHasCookie()`` +- ``assertResponseCookieValueSame()`` + +Request +~~~~~~~ + +- ``assertRequestAttributeValueSame()`` +- ``assertRouteSame()`` + +Browser +~~~~~~~ + +- ``assertBrowserHasCookie()`` +- ``assertBrowserNotHasCookie()`` +- ``assertBrowserCookieValueSame()`` + +Crawler +~~~~~~~ + +- ``assertSelectorExists()`` +- ``assertSelectorNotExists()`` +- ``assertSelectorTextContains()`` +- ``assertSelectorTextSame()`` +- ``assertSelectorTextNotContains()`` +- ``assertPageTitleSame()`` +- ``assertPageTitleContains()`` +- ``assertInputValueSame()`` +- ``assertInputValueNotSame()`` + +Troubleshooting +--------------- + +These assertions will not work with `symfony/panther`_ as they use the +``Request`` and ``Response`` objects from the ``HttpFoundation`` +component, and the ``KernelBrowser`` from the ``FrameworkBundle``. +Panther only uses the ``BrowserKit`` component. + +.. _`symfony/panther`: https://github.com/symfony/panther From d9b4121f53e7f6572476de2e6cd1c8c032b28482 Mon Sep 17 00:00:00 2001 From: fancyweb Date: Sun, 7 Apr 2019 10:34:53 +0200 Subject: [PATCH 092/499] [Routing] Invokable route loader services --- routing/custom_route_loader.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/routing/custom_route_loader.rst b/routing/custom_route_loader.rst index b99c6292d24..70126b473ac 100644 --- a/routing/custom_route_loader.rst +++ b/routing/custom_route_loader.rst @@ -133,6 +133,15 @@ extend or implement any special class, but the called method must return a cached by the framework. So whenever your service should load new routes, don't forget to clear the cache. +.. tip:: + + 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 ------------------------ From 85220e1e33ee827574d936ca569f09a2311b5f4d Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Sat, 8 Dec 2018 14:11:32 +0100 Subject: [PATCH 093/499] Documentation workflow context apply --- contributing/documentation/overview.rst | 5 ++ workflow.rst | 5 +- workflow/state-machines.rst | 27 ++++++++ workflow/usage.rst | 82 ++++++++++++++++++++++++- 4 files changed, 114 insertions(+), 5 deletions(-) diff --git a/contributing/documentation/overview.rst b/contributing/documentation/overview.rst index bd0c9564ab4..dbeb608f839 100644 --- a/contributing/documentation/overview.rst +++ b/contributing/documentation/overview.rst @@ -284,6 +284,10 @@ If you don't use Docker, follow these steps to build the docs locally: The generated documentation is available in the ``_build/html`` directory. +.. tip:: + + You can also use `Docker`_ that wraps all this for you! + Frequently Asked Questions -------------------------- @@ -346,3 +350,4 @@ definitely don't want you to waste your time! .. _`pip installation`: https://pip.pypa.io/en/stable/installing/ .. _`Sphinx`: http://sphinx-doc.org/ .. _`Sphinx Extensions for PHP and Symfony`: https://github.com/fabpot/sphinx-php +.. _`Docker`: https://github.com/symfony/symfony-docs#docker diff --git a/workflow.rst b/workflow.rst index b25e62b8379..d08b2d8e819 100644 --- a/workflow.rst +++ b/workflow.rst @@ -8,8 +8,9 @@ best kept away from your models and should be defined in configuration. A **definition** of a workflow consist of places and actions to get from one place to another. The actions are called **transitions**. A workflow does also -need to know each object's position in the workflow. That **marking store** writes -to a property of the object to remember the current place. +need to know each position an object can be in the workflow. This is the goal of the +**marking store** that reads from and writes to a property of the object, or somewhere else, the current **place(s)** +to remember. .. note:: diff --git a/workflow/state-machines.rst b/workflow/state-machines.rst index 3caf48b6c06..cb2c01ce5e8 100644 --- a/workflow/state-machines.rst +++ b/workflow/state-machines.rst @@ -209,6 +209,33 @@ you can get this state machine by injecting the Workflow registry service:: public function someMethod($subject) { $stateMachine = $this->workflows->get($subject, 'pull_request'); + $stateMachine->apply($subject, 'wait_for_review'); + // ... + } + + // ... + } + +Symfony also creates automatically for you a service for each workflow (:class:`Symfony\\Component\\Workflow\\Workflow`) or state machine (:class:`Symfony\\Component\\Workflow\\StateMachine`) you have defined in your configuration. +This means that you can use respectively ``workflow.pull_request`` or ``state_machine.pull_request`` in your service definition to have directly the proper service:: + + // ... + use Symfony\Component\Workflow\StateMachine; + + class SomeService + { + private $stateMachine; + + public function __construct(StateMachine $stateMachine) + { + $this->stateMachine = $stateMachine; + } + + public function someMethod($subject) + { + $this->stateMachine->apply($subject, 'wait_for_review', [ + 'log_comment' => 'My logging comment for the wait for review transition.', + ]); // ... } diff --git a/workflow/usage.rst b/workflow/usage.rst index 57fc4eb79dc..1721e9c352c 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -43,7 +43,7 @@ like this: audit_trail: enabled: true marking_store: - type: 'multiple_state' # or 'single_state' + type: 'multiple_state' # or 'single_state', 'method' ('method' was added in 4.3) arguments: - 'currentPlace' supports: @@ -126,7 +126,7 @@ like this: 'enabled' => true ], 'marking_store' => [ - 'type' => 'multiple_state', // or 'single_state' + 'type' => 'multiple_state', // or 'single_state', 'method' ('method' was added in 4.3) 'arguments' => ['currentPlace'], ], 'supports' => ['App\Entity\BlogPost'], @@ -166,7 +166,7 @@ As configured, the following property is used by the marking store:: .. note:: - The marking store type could be "multiple_state" or "single_state". + The marking store type could be "multiple_state", "single_state" or "method". A single state marking store does not support a model being on multiple places at the same time. @@ -220,11 +220,87 @@ you can get the workflow by injecting the Workflow registry service:: // ... if the transition is not allowed } + // Update the currentState on the post passing some contextual data + // to the whole workflow process + try { + $workflow->apply($post, 'publish', [ + 'log_comment' => 'My logging comment for the publish transition.', + ]); + } catch (TransitionException $exception) { + // ... if the transition is not allowed + } + // See all the available transitions for the post in the current state $transitions = $workflow->getEnabledTransitions($post); } } +.. versionadded:: 4.1 + + The :class:`Symfony\\Component\\Workflow\\Exception\\TransitionException` + class was introduced in Symfony 4.1. + +.. versionadded:: 4.1 + + The :method:`Symfony\\Component\\Workflow\\Registry::all` method was + introduced in Symfony 4.1. + +.. versionadded:: 4.3 + + The :method:`Symfony\\Component\\Workflow\\Workflow::apply` has now a new parameter ``$context`` + that is passed to the :class:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface` + :method:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface::setMarking` method. + +An example of usage with the ``$context`` parameter can be when you need, +in addition of marking your object in its new place, to contextualize this change. + +.. tip:: + + Configure the ``type`` as ``method`` of the ``marking_store`` option to use this feature + without implementing your own marking store. + +You can also use this ``$context`` in your own marking store implementation. +A simple implementation example is when you want to store the place as integer instead of string in your object. + +Lets say your object has a status property, stored as an integer in your storage, and you want to log an optional +comment any time the status changes:: + + // your own implementation class, to define in the configuration "marking_store" + + class ObjectMarkingStore implements MarkingStoreInterface + { + public function getMarking($subject) + { + $subject->getStatus(); + // ... + // return a marking + } + + public function setMarking($subject, Marking $marking, array $context); + { + // ... + $subject->setStatus($newStatus, $context['log_comment'] ?? null); + } + } + + // and in your Object class + + public function getStatus() + { + return $this->status; + } + + public function setStatus(int $status, ?string $comment = null) + { + $this->status = $status; + $this->addStatusLogRecord(new StatusLog($this, $comment)); + + return $this; + } + + // the StatusLog class can have a createdAt, a username, + // the new status, and finally your optional comment retrieved from the workflow context. + Using Events ------------ From e1e4efcd707cfa7489d6df4ba47a6d1be4a308ea Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 7 Apr 2019 13:40:46 +0200 Subject: [PATCH 094/499] [#10751] some minor tweaks --- contributing/documentation/overview.rst | 5 ----- workflow/state-machines.rst | 7 +++++-- workflow/usage.rst | 23 +++++++++++++++-------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/contributing/documentation/overview.rst b/contributing/documentation/overview.rst index dbeb608f839..bd0c9564ab4 100644 --- a/contributing/documentation/overview.rst +++ b/contributing/documentation/overview.rst @@ -284,10 +284,6 @@ If you don't use Docker, follow these steps to build the docs locally: The generated documentation is available in the ``_build/html`` directory. -.. tip:: - - You can also use `Docker`_ that wraps all this for you! - Frequently Asked Questions -------------------------- @@ -350,4 +346,3 @@ definitely don't want you to waste your time! .. _`pip installation`: https://pip.pypa.io/en/stable/installing/ .. _`Sphinx`: http://sphinx-doc.org/ .. _`Sphinx Extensions for PHP and Symfony`: https://github.com/fabpot/sphinx-php -.. _`Docker`: https://github.com/symfony/symfony-docs#docker diff --git a/workflow/state-machines.rst b/workflow/state-machines.rst index cb2c01ce5e8..4a5952c9f1d 100644 --- a/workflow/state-machines.rst +++ b/workflow/state-machines.rst @@ -216,8 +216,11 @@ you can get this state machine by injecting the Workflow registry service:: // ... } -Symfony also creates automatically for you a service for each workflow (:class:`Symfony\\Component\\Workflow\\Workflow`) or state machine (:class:`Symfony\\Component\\Workflow\\StateMachine`) you have defined in your configuration. -This means that you can use respectively ``workflow.pull_request`` or ``state_machine.pull_request`` in your service definition to have directly the proper service:: +Symfony automatically creates a service for each workflow (:class:`Symfony\\Component\\Workflow\\Workflow`) +or state machine (:class:`Symfony\\Component\\Workflow\\StateMachine`) you +have defined in your configuration. This means that you can use ``workflow.pull_request`` +or ``state_machine.pull_request`` respectively in your service definitions +to access the proper service:: // ... use Symfony\Component\Workflow\StateMachine; diff --git a/workflow/usage.rst b/workflow/usage.rst index 1721e9c352c..c613b76dd3a 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -43,7 +43,7 @@ like this: audit_trail: enabled: true marking_store: - type: 'multiple_state' # or 'single_state', 'method' ('method' was added in 4.3) + type: 'multiple_state' # one of 'single_state', 'multiple_state', 'method' arguments: - 'currentPlace' supports: @@ -126,7 +126,7 @@ like this: 'enabled' => true ], 'marking_store' => [ - 'type' => 'multiple_state', // or 'single_state', 'method' ('method' was added in 4.3) + 'type' => 'multiple_state', // one of 'single_state', 'multiple_state', 'method' 'arguments' => ['currentPlace'], ], 'supports' => ['App\Entity\BlogPost'], @@ -170,6 +170,10 @@ As configured, the following property is used by the marking store:: A single state marking store does not support a model being on multiple places at the same time. + versionadded:: 4.3 + + The ``method`` marking store type was introduced in Symfony 4.3. + .. tip:: The ``type`` (default value ``single_state``) and ``arguments`` (default @@ -245,14 +249,17 @@ you can get the workflow by injecting the Workflow registry service:: The :method:`Symfony\\Component\\Workflow\\Registry::all` method was introduced in Symfony 4.1. -.. versionadded:: 4.3 +You can pass some context as the second argument of the ``apply()`` method. +This can be useful when the subject not only needs to apply a transition, +but for example you also want to log the context in which the switch happened. - The :method:`Symfony\\Component\\Workflow\\Workflow::apply` has now a new parameter ``$context`` - that is passed to the :class:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface` - :method:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface::setMarking` method. +This context is forwarded to the :method:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface::setMarking` +method of the marking store. + +.. versionadded:: 4.3 -An example of usage with the ``$context`` parameter can be when you need, -in addition of marking your object in its new place, to contextualize this change. + The ``$context`` argument of the :method:`Symfony\\Component\\Workflow\\Workflow::apply` + method was introduced in Symfony 4.3. .. tip:: From 7ea06fae8dd41a79d7100d6b2b99aab73e99f8d4 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Sun, 7 Apr 2019 14:56:42 +0200 Subject: [PATCH 095/499] document DEEP_OBJECT_TO_POPULATE --- components/serializer.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/serializer.rst b/components/serializer.rst index 5bb34d24a7a..d2fed246e43 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -210,6 +210,20 @@ The serializer can also be used to update an existing object:: This is a common need when working with an ORM. +The ``OBJECT_TO_POPULATE`` is only used for the top level object. If that object +is the root of a tree structure, all child elements that exist in the +normalized data will be re-created with new instances. + +..versionadded:: 4.3 + + Symfony 4.3 introduces a new option ``AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE``. + When this flag is set to true, existing children of the root ``OBJECT_TO_POPULATE`` are + updated from the normalized data, instead of the denormalizer re-creating them. + + Note that ``DEEP_OBJECT_TO_POPULATE`` only works for single child objects, + but not for arrays of objects. Those will still be replaces when present in + the normalized data. + .. _component-serializer-attributes-groups: Attributes Groups From 75febdc46fccae2e35960d3f7855262c5f875562 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Sun, 7 Apr 2019 10:03:53 +0000 Subject: [PATCH 096/499] [HttpKernel] Document `trace_level` and `trace_header` config options in `HttpCache` --- http_cache.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/http_cache.rst b/http_cache.rst index dfcb843c1b2..77797be953e 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -155,7 +155,26 @@ For a full list of the options and their meaning, see the 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`` -header to the response. Use this to get information about cache hits and misses. +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. +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. +This information can be used to extract general information about +cache efficiency of your routes. + +.. tip:: + + You can change the name of the header used for the trace + information using the ``trace_header`` config option. + +.. versionadded:: 4.3 + + The ``trace_level`` and ``trace_header`` configuration options + were introduced in Symfony 4.3. .. _http-cache-symfony-versus-varnish: From fed4d14a276ffaab185b80c8d9c9f875b3eb60c1 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Sun, 7 Apr 2019 22:21:16 +0200 Subject: [PATCH 097/499] [#11344] Some minor formatting changes --- components/serializer.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/components/serializer.rst b/components/serializer.rst index d2fed246e43..0997e45f9a7 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -214,15 +214,17 @@ The ``OBJECT_TO_POPULATE`` is only used for the top level object. If that object is the root of a tree structure, all child elements that exist in the normalized data will be re-created with new instances. -..versionadded:: 4.3 +When the ``AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE`` option is set to +true, existing children of the root ``OBJECT_TO_POPULATE`` are updated from the +normalized data, instead of the denormalizer re-creating them. Note that +``DEEP_OBJECT_TO_POPULATE`` only works for single child objects, but not for +arrays of objects. Those will still be replaced when present in the normalized +data. - Symfony 4.3 introduces a new option ``AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE``. - When this flag is set to true, existing children of the root ``OBJECT_TO_POPULATE`` are - updated from the normalized data, instead of the denormalizer re-creating them. +.. versionadded:: 4.3 - Note that ``DEEP_OBJECT_TO_POPULATE`` only works for single child objects, - but not for arrays of objects. Those will still be replaces when present in - the normalized data. + The ``AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE`` option was + introduced in Symfony 4.3. .. _component-serializer-attributes-groups: From 1011b420844179cc1ae140773102a688cf358321 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Sat, 6 Apr 2019 14:04:37 +0000 Subject: [PATCH 098/499] Add documentation for the `require` env processor --- configuration/environment_variables.rst | 45 +++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/configuration/environment_variables.rst b/configuration/environment_variables.rst index 50a2bd77daf..11b8f44edc3 100644 --- a/configuration/environment_variables.rst +++ b/configuration/environment_variables.rst @@ -445,6 +445,51 @@ Symfony provides the following env var processors: 'auth' => '%env(file:AUTH_FILE)%', ]); +``env(require:FOO)`` + ``require()`` the PHP file whose path is the value of the ``FOO`` + env var and return the value returned from it. + + .. configuration-block:: + + .. code-block:: yaml + + # config/packages/framework.yaml + parameters: + env(PHP_FILE): '../config/.runtime-evaluated.php' + app: + auth: '%env(require:PHP_FILE)%' + + .. code-block:: xml + + + + + + + ../config/.runtime-evaluated.php + + + + + + .. code-block:: php + + // config/packages/framework.php + $container->setParameter('env(PHP_FILE)', '../config/.runtime-evaluated.php'); + $container->loadFromExtension('app', [ + '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 From eb45f741456d9bd605167b584ef09f4342d3c9ec Mon Sep 17 00:00:00 2001 From: vermeirentony Date: Mon, 8 Apr 2019 07:30:53 +0200 Subject: [PATCH 099/499] Update NotCompromisedPassword.rst Added missing word --- reference/constraints/NotCompromisedPassword.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/constraints/NotCompromisedPassword.rst b/reference/constraints/NotCompromisedPassword.rst index 30a43828ed1..b82db2c3efd 100644 --- a/reference/constraints/NotCompromisedPassword.rst +++ b/reference/constraints/NotCompromisedPassword.rst @@ -5,7 +5,7 @@ NotCompromisedPassword The ``NotCompromisedPassword`` constraint was introduced in Symfony 4.3. -Validates that the given password has not been compromised by checking that is +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`_. ========== =================================================================== From 038d9b7ebaab04adf1319810746a3b0927180d63 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 8 Apr 2019 08:45:39 +0200 Subject: [PATCH 100/499] Documented the disable_not_compromised_password option --- reference/configuration/framework.rst | 21 +++++++++++++++++++ .../constraints/NotCompromisedPassword.rst | 6 ++++++ 2 files changed, 27 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index f4647014e4b..9cdf62fa66c 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -184,6 +184,7 @@ Configuration * `validation`_ * :ref:`cache ` + * :ref:`disable_not_compromised_password ` * `email_validation_mode`_ * :ref:`enable_annotations ` * :ref:`enabled ` @@ -1777,6 +1778,26 @@ has to implement the :class:`Symfony\\Component\\Validator\\Mapping\\Cache\\Cach Set this option to ``validator.mapping.cache.doctrine.apc`` to use the APC cache provide from the Doctrine project. +.. _reference-validation-disable_not_compromised_password: + +disable_not_compromised_password +................................ + +**type**: ``boolean`` **default**: ``false`` + +.. versionadded:: 4.3 + + The ``disable_not_compromised_password`` option was introduced in Symfony 4.3. + +The :doc:`NotCompromisedPassword ` +constraint makes HTTP requests to a public API to check if the given password +has been compromised in a data breach. + +If you set this option to ``true``, no HTTP requests will be made and the given +password will be considered valid. This is useful when you don't want or can't +make HTTP requests, such as in ``dev`` and ``test`` environments or in +continuous integration servers. + .. _reference-validation-enable_annotations: enable_annotations diff --git a/reference/constraints/NotCompromisedPassword.rst b/reference/constraints/NotCompromisedPassword.rst index 30a43828ed1..81de2804f9a 100644 --- a/reference/constraints/NotCompromisedPassword.rst +++ b/reference/constraints/NotCompromisedPassword.rst @@ -97,6 +97,12 @@ For example, if the password is ``test``, the entire SHA-1 hash is ``a94a8fe5ccb19ba61c4c0873d391e987982fbbd3`` but the validator only sends ``a94a8`` to the ``haveibeenpwned.com`` API. +.. seealso:: + + When using this constraint inside a Symfony application, define the + :ref:`disable_not_compromised_password ` + option to avoid making HTTP requests in the ``dev`` and ``test`` environments. + Available Options ----------------- From e1636aa5cde488c803b00eb75a4649d6b741c52a Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Mon, 8 Apr 2019 20:21:08 +0200 Subject: [PATCH 101/499] Show how to list all available pools --- cache.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cache.rst b/cache.rst index 830988891ea..743b3369d75 100644 --- a/cache.rst +++ b/cache.rst @@ -419,6 +419,12 @@ The global clearer clears all the cache in every pool. The system cache clearer is used in the ``bin/console cache:clear`` command. The app clearer is the default clearer. +To see all available cache pools: + +.. code-block:: terminal + + $ php bin/console cache:pool:list + Clear one pool: .. code-block:: terminal From 3421c6cf056409fbaf546aff46b284d5b432e05f Mon Sep 17 00:00:00 2001 From: Piotr Stankowski Date: Tue, 9 Apr 2019 11:43:35 +0200 Subject: [PATCH 102/499] [MonologBridge] Add documentation on new processors --- logging/processors.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/logging/processors.rst b/logging/processors.rst index c5479db697c..310764b1fe8 100644 --- a/logging/processors.rst +++ b/logging/processors.rst @@ -172,10 +172,20 @@ Symfony's MonologBridge provides processors that can be registered inside your a :class:`Symfony\\Bridge\\Monolog\\Processor\\WebProcessor` Overrides data from the request using the data inside Symfony's request object. + +:class:`Symfony\\Bridge\\Monolog\\Processor\\RouteProcessor` + Adds information about current route (controller, action, route parameters). + +:class:`Symfony\\Bridge\\Monolog\\Processor\\ConsoleCommandProcessor` + Adds information about current console command. .. versionadded:: 3.4 The ``TokenProcessor`` class was introduced in Symfony 3.4. + +.. versionadded:: 4.3 + + The ``RouteProcessor`` and the ``ConsoleCommandProcessor`` were introduced in Symfony 4.3. Registering Processors per Handler ---------------------------------- From 5cfc67e595f1976621bc4f569b54950e5caf6d45 Mon Sep 17 00:00:00 2001 From: Mikkel Paulson Date: Sun, 7 Apr 2019 21:45:28 -0400 Subject: [PATCH 103/499] Add description of autocompleter callback Documented feature added by symfony/symfony#30997. --- components/console/helpers/questionhelper.rst | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index 60651b83e5f..8edcbf9370c 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -179,6 +179,52 @@ will be autocompleted as the user types:: $bundleName = $helper->ask($input, $output, $question); } +In more complex use cases, it may be necessary to generate suggestions on the +fly, for instance if you wish to autocomplete a file path. In that case, you can +provide a callback function to dynamically generate suggestions:: + + use Symfony\Component\Console\Question\Question; + + // ... + public function execute(InputInterface $input, OutputInterface $output) + { + // This function is called whenever the input changes and new + // suggestions are needed. + $callback = function (string $input): array { + // Strip any characters from the last slash to the end of the + // string - this is considered a complete path and should populate + // our autocomplete suggestions. + $inputPath = preg_replace( + '%(/|^)[^/]*$%', + '$1', + $input + ); + + // All suggestions should start with the input the user has already + // provided (existing path), followed in this case by the contents + // of the referenced directory. Some suggestions may be ignored + // because they don't match the full string provided by the user, + // but the autocomplete helper will take care of that for us. + return array_map( + function ($suggestion) use ($inputPath) { + return $inputPath . $suggestion; + }, + @scandir($inputPath === '' ? '.' : $inputPath) ?: [] + ); + }; + + $question = new Question('Please provide the full path of a file to parse'); + $question->setAutocompleterCallback($callback); + + $filePath = $this->output->askQuestion($question); + } + +.. caution:: + + This example code allows unrestricted access to the host filesystem, and + should only ever be used in a local context, such as in a script being + manually invoked from the command line on a server you control. + Hiding the User's Response ~~~~~~~~~~~~~~~~~~~~~~~~~~ From 9af9d577eeb29cfacf72a2c2e7d3fd3543d4a6aa Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 9 Apr 2019 15:30:33 +0200 Subject: [PATCH 104/499] Tweaks --- components/console/helpers/questionhelper.rst | 41 ++++++++----------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index 8edcbf9370c..351ee10edff 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -191,39 +191,30 @@ provide a callback function to dynamically generate suggestions:: // This function is called whenever the input changes and new // suggestions are needed. $callback = function (string $input): array { - // Strip any characters from the last slash to the end of the - // string - this is considered a complete path and should populate - // our autocomplete suggestions. - $inputPath = preg_replace( - '%(/|^)[^/]*$%', - '$1', - $input - ); - - // All suggestions should start with the input the user has already - // provided (existing path), followed in this case by the contents - // of the referenced directory. Some suggestions may be ignored - // because they don't match the full string provided by the user, - // but the autocomplete helper will take care of that for us. - return array_map( - function ($suggestion) use ($inputPath) { - return $inputPath . $suggestion; - }, - @scandir($inputPath === '' ? '.' : $inputPath) ?: [] - ); + // Strip any characters from the last slash to the end of the string + // to keep only the last directory and generate suggestions for it + $inputPath = preg_replace('%(/|^)[^/]*$%', '$1', $userInput); + $inputPath = '' === $inputPath ? '.' : $inputPath; + + // CAUTION - this example code allows unrestricted access to the + // entire filesystem. In real applications, restrict the directories + // where files and dirs can be found + $foundFilesAndDirs = @scandir($inputPath) ?: []; + + return array_map(function ($dirOrFile) use ($inputPath) { + return $inputPath.$dirOrFile; + }, $foundFilesAndDirs); }; $question = new Question('Please provide the full path of a file to parse'); $question->setAutocompleterCallback($callback); - $filePath = $this->output->askQuestion($question); + $filePath = $helper->ask($input, $output, $question); } -.. caution:: +.. versionadded:: 4.3 - This example code allows unrestricted access to the host filesystem, and - should only ever be used in a local context, such as in a script being - manually invoked from the command line on a server you control. + The ``setAutocompleterCallback()`` method was introduced in Symfony 4.3. Hiding the User's Response ~~~~~~~~~~~~~~~~~~~~~~~~~~ From 57fadafdb452b69386cb13db453d986e9e166940 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 27 Mar 2019 16:39:27 +0100 Subject: [PATCH 105/499] Documented the deprecation of the Templating component --- form/create_custom_field_type.rst | 47 --------------------------- reference/configuration/framework.rst | 6 ++++ reference/dic_tags.rst | 5 +++ templating/PHP.rst | 12 +++++++ templating/hinclude.rst | 12 +++++-- 5 files changed, 32 insertions(+), 50 deletions(-) diff --git a/form/create_custom_field_type.rst b/form/create_custom_field_type.rst index 9023f0c9d40..b67c0a330d8 100644 --- a/form/create_custom_field_type.rst +++ b/form/create_custom_field_type.rst @@ -185,8 +185,6 @@ link for details), create a ``shipping_widget`` block to handle this: rules). Further, the main config file should point to the custom form template so that it's used when rendering all forms. - When using Twig this is: - .. configuration-block:: .. code-block:: yaml @@ -222,51 +220,6 @@ link for details), create a ``shipping_widget`` block to handle this: ], ]); - For the PHP templating engine, your configuration should look like this: - - .. configuration-block:: - - .. code-block:: yaml - - # config/packages/framework.yaml - framework: - templating: - form: - resources: - - ':form:fields.html.php' - - .. code-block:: xml - - - - - - - - - :form:fields.html.php - - - - - - .. code-block:: php - - // config/packages/framework.php - $container->loadFromExtension('framework', [ - 'templating' => [ - 'form' => [ - 'resources' => [ - ':form:fields.html.php', - ], - ], - ], - ]); - Using the Field Type -------------------- diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 0f54eecbf74..bae4ddbf899 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1554,6 +1554,12 @@ 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 `. diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 1aca88bb444..5b8cacddeb5 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -794,6 +794,11 @@ 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 diff --git a/templating/PHP.rst b/templating/PHP.rst index bc9a0d61149..d0b218292b6 100644 --- a/templating/PHP.rst +++ b/templating/PHP.rst @@ -4,6 +4,12 @@ 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 @@ -17,6 +23,12 @@ templates with PHP more powerful. 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 diff --git a/templating/hinclude.rst b/templating/hinclude.rst index 675fd268607..396dec13643 100644 --- a/templating/hinclude.rst +++ b/templating/hinclude.rst @@ -67,7 +67,7 @@ in your application configuration: # config/packages/framework.yaml framework: # ... - templating: + fragments: hinclude_default_template: hinclude.html.twig .. code-block:: xml @@ -83,7 +83,7 @@ in your application configuration: - +
@@ -92,13 +92,19 @@ in your application configuration: // config/packages/framework.php $container->loadFromExtension('framework', [ // ... - 'templating' => [ + 'fragments' => [ 'hinclude_default_template' => [ 'hinclude.html.twig', ], ], ]); +.. 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): From 6eba77c6764f925f1bb50dd558b861e1b5051e41 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Tue, 9 Apr 2019 21:37:03 +0200 Subject: [PATCH 106/499] Revert "[#11375] Removed the workflow_transition_blockers from 4.2 docs" in 4.3 This reverts commit f673d4d08a650d6da35eceed1917aa56e0b4edb7. --- workflow/usage.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/workflow/usage.rst b/workflow/usage.rst index 86c1bb069d1..e718f92edb0 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -588,6 +588,31 @@ transition was blocked:: } } +You can access the message from a Twig template as follows: + +.. code-block:: html+twig + +

Publication was blocked because:

+
    + {% for transition in workflow_all_transitions(article) %} + {% if not workflow_can(article, transition.name) %} +
  • + {{ transition.name }}: +
      + {% for blocker in workflow_transition_blockers(article, transition.name) %} +
    • + {{ blocker.message }} + {% if blocker.parameters.expression is defined %} + {{ blocker.parameters.expression }} + {% endif %} +
    • + {% endfor %} +
    +
  • + {% endif %} + {% endfor %} +
+ Don't need a human-readable message? You can still use:: $event->setBlocked('true'); From 13c92ff23cfc609c3455534b2630bcdf4da6d4b7 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Tue, 9 Apr 2019 21:37:52 +0200 Subject: [PATCH 107/499] [#11375] Added versionadded --- workflow/usage.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/workflow/usage.rst b/workflow/usage.rst index e718f92edb0..bab6e4b0c01 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -613,6 +613,11 @@ You can access the message from a Twig template as follows: {% endfor %} +.. versionadded:: 4.3 + + The ``workflow_transition_blockers()`` Twig function was introduced in + Symfony 4.3. + Don't need a human-readable message? You can still use:: $event->setBlocked('true'); From 8bd49317ce008ff229f97c729fd1482f8b0e845e Mon Sep 17 00:00:00 2001 From: Wouter J Date: Wed, 10 Apr 2019 14:42:35 +0200 Subject: [PATCH 108/499] [#11369] Added versionadded --- cache.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cache.rst b/cache.rst index 4b4bc175961..d3c00cb89cd 100644 --- a/cache.rst +++ b/cache.rst @@ -644,6 +644,10 @@ 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 From 56ed618b74a5cfddaffee807d0f70bf2b6e81946 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 10 Apr 2019 17:32:12 +0200 Subject: [PATCH 109/499] fixed the name of a variable --- components/console/helpers/questionhelper.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index 351ee10edff..0d69c7c969c 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -190,7 +190,7 @@ provide a callback function to dynamically generate suggestions:: { // This function is called whenever the input changes and new // suggestions are needed. - $callback = function (string $input): array { + $callback = function (string $userInput): array { // Strip any characters from the last slash to the end of the string // to keep only the last directory and generate suggestions for it $inputPath = preg_replace('%(/|^)[^/]*$%', '$1', $userInput); From 1c90ee52502cb81f026e8b9c67bac3345f4fd451 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 11 Apr 2019 11:35:58 +0200 Subject: [PATCH 110/499] Minor tweaks in the Timezone validator docs --- reference/constraints/Timezone.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index c06f4ae92d6..070708ccc11 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -38,7 +38,7 @@ string meant to contain a timezone identifier (e.g. ``America/New_York``): /** * @Assert\Timezone */ - protected $timezone; + protected $timezone; } .. code-block:: yaml @@ -125,12 +125,13 @@ identifiers to the ones that belong to that geographical zone: * ``\DateTimeZone::INDIAN`` * ``\DateTimeZone::PACIFIC`` -The special ``\DateTimeZone::ALL`` zone accepts any timezone excluding deprecated timezones. - -The special ``\DateTimeZone::ALL_WITH_BC`` zone accepts any timezone including deprecated timezones. +In addition, there are some special zone values: -The special ``\DateTimeZone::PER_COUNTRY`` zone limits the timezones to a certain country. This zone -value must be used in combination with the ``countryCode`` option. +* ``\DateTimeZone::ALL`` accepts any timezone excluding deprecated timezones; +* ``\DateTimeZone::ALL_WITH_BC`` accepts any timezone including deprecated + timezones; +* ``\DateTimeZone::PER_COUNTRY`` restricts the valid timezones to a certain + country (which is defined using the ``countryCode`` option). countryCode ~~~~~~~~~~~ From ae1a7ab1496e66531c9421463620f7798d64d8f7 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 11 Apr 2019 11:39:24 +0200 Subject: [PATCH 111/499] Move Timezone under Date constraints --- reference/constraints.rst | 2 +- reference/constraints/map.rst.inc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/constraints.rst b/reference/constraints.rst index cb311dc2974..317a836e396 100644 --- a/reference/constraints.rst +++ b/reference/constraints.rst @@ -41,6 +41,7 @@ Validation Constraints Reference constraints/Date constraints/DateTime constraints/Time + constraints/Timezone constraints/Choice constraints/Collection @@ -49,7 +50,6 @@ Validation Constraints Reference constraints/Language constraints/Locale constraints/Country - constraints/Timezone constraints/File constraints/Image diff --git a/reference/constraints/map.rst.inc b/reference/constraints/map.rst.inc index ec2d307f6ad..337798c51da 100644 --- a/reference/constraints/map.rst.inc +++ b/reference/constraints/map.rst.inc @@ -53,6 +53,7 @@ Date Constraints * :doc:`Date ` * :doc:`DateTime ` * :doc:`Time ` +* :doc:`Timezone ` Choice Constraints ~~~~~~~~~~~~~~~~~~ @@ -61,7 +62,6 @@ Choice Constraints * :doc:`Language ` * :doc:`Locale ` * :doc:`Country ` -* :doc:`Timezone ` File Constraints ~~~~~~~~~~~~~~~~ From b3b39b0a9b856343736a39e95844506602cbba33 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 11 Apr 2019 21:46:02 +0200 Subject: [PATCH 112/499] small constraint improvements --- reference/constraints/Json.rst | 4 +--- reference/constraints/Timezone.rst | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/reference/constraints/Json.rst b/reference/constraints/Json.rst index 1fdcaaffd12..4590b847c57 100644 --- a/reference/constraints/Json.rst +++ b/reference/constraints/Json.rst @@ -35,7 +35,7 @@ The ``Json`` constraint can be applied to a property or a "getter" method: * message = "You've entered an invalid Json." * ) */ - private $chapters; + private $chapters; } .. code-block:: yaml @@ -74,8 +74,6 @@ The ``Json`` constraint can be applied to a property or a "getter" method: class Book { - private $chapters; - public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('chapters', new Assert\Json([ diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 070708ccc11..2fc04bdc839 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -74,8 +74,6 @@ string meant to contain a timezone identifier (e.g. ``America/New_York``): class UserSettings { - protected $timezone; - public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('timezone', new Assert\Timezone()); From 112184bcca1c43c6760de303dc3a3446caa3cf17 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 11 Apr 2019 22:19:32 +0200 Subject: [PATCH 113/499] small improvements --- components/mime.rst | 12 ++-- components/property_access.rst | 2 +- components/routing.rst | 2 +- configuration/environment_variables.rst | 4 +- routing.rst | 2 +- service_container/configurators.rst | 88 +++++++++++++------------ service_container/factories.rst | 4 +- 7 files changed, 58 insertions(+), 56 deletions(-) diff --git a/components/mime.rst b/components/mime.rst index 34b06cd40de..62bb707ebdb 100644 --- a/components/mime.rst +++ b/components/mime.rst @@ -156,7 +156,7 @@ images inside the HTML contents:: ->embed(fopen('/path/to/images/logo.png', 'r'), 'logo') ->embedFromPath('/path/to/images/signature.gif', 'footer-signature') // reference images using the syntax 'cid:' + "image embed name" - ->html(' ... ...') + ->html(' ... ...') ; File Attachments @@ -251,7 +251,7 @@ email multiparts:: $textContent = new TextPart('Lorem ipsum...'); $htmlContent = new TextPart(sprintf( - '

Lorem ipsum

...

', $imageCid + '

Lorem ipsum

...

', $imageCid ), 'html'); $bodyContent = new AlternativePart($textContent, $htmlContent); $body = new RelatedPart($bodyContent, $embeddedImage); @@ -390,7 +390,7 @@ the ``TemplatedEmail`` class:: Embedding Images in Emails with Twig ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Instead of dealing with the ```` syntax explained in the +Instead of dealing with the ```` syntax explained in the previous sections, when using Twig to render email contents you can refer to image files as usual. First, define a Twig namespace called ``images`` to simplify things later:: @@ -407,7 +407,7 @@ the email contents: .. code-block:: html+twig {# '@images/' refers to the Twig namespace defined earlier #} - +

Welcome {{ username }}!

{# ... #} @@ -495,7 +495,7 @@ Now, enable the extension (this is done automatically in Symfony applications):: Finally, use the ``markdown`` filter to convert parts or the entire email contents from Markdown to HTML: -.. code-block:: html+twig +.. code-block:: twig {% filter markdown %} Welcome {{ username }}! @@ -560,7 +560,7 @@ contents from Inky to HTML: You can combine all filters to create complex email messages: -.. code-block:: html+twig +.. code-block:: twig {% filter inky|inline_css(source('@zurb/stylesheets/main.css')) %} {# ... #} diff --git a/components/property_access.rst b/components/property_access.rst index e0b13a6dca8..c362da2da22 100644 --- a/components/property_access.rst +++ b/components/property_access.rst @@ -176,7 +176,7 @@ Accessing a non Existing Property Path 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 behaviour using the +does not exist. You can change this behavior using the :method:`Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder::disableExceptionOnInvalidPropertyPath` method:: diff --git a/components/routing.rst b/components/routing.rst index 4bd5297e858..2eaf0fbf294 100644 --- a/components/routing.rst +++ b/components/routing.rst @@ -482,7 +482,7 @@ routes with UTF-8 characters: + https://symfony.com/schema/routing/routing-1.0.xsd"> + https://symfony.com/schema/dic/services/services-1.0.xsd"> @@ -695,7 +695,7 @@ Symfony provides the following env var processors: + https://symfony.com/schema/dic/services/services-1.0.xsd"> diff --git a/routing.rst b/routing.rst index 696d2a4e5cf..b46ac124b93 100644 --- a/routing.rst +++ b/routing.rst @@ -805,7 +805,7 @@ You can also use special attributes to configure them (except ``_fragment``): + https://symfony.com/schema/routing/routing-1.0.xsd"> `. -.. code-block:: yaml +.. configuration-block:: - # config/services.yaml - services: - # ... + .. code-block:: yaml - # registers all classes as services, including App\Mail\EmailConfigurator - App\: - resource: '../src/*' + # config/services.yaml + services: # ... - # override the services to set the configurator - App\Mail\NewsletterManager: - configurator: '@App\Mail\EmailConfigurator' + # registers all classes as services, including App\Mail\EmailConfigurator + App\: + resource: '../src/*' + # ... - App\Mail\GreetingCardManager: - configurator: '@App\Mail\EmailConfigurator' + # override the services to set the configurator + App\Mail\NewsletterManager: + configurator: '@App\Mail\EmailConfigurator' -.. code-block:: xml + App\Mail\GreetingCardManager: + configurator: '@App\Mail\EmailConfigurator' - - - + .. code-block:: xml - - + + + - - - + + - - - - - + + + -.. code-block:: php + + + + + - // config/services.php - use App\Mail\GreetingCardManager; - use App\Mail\NewsletterManager; - use Symfony\Component\DependencyInjection\Definition; - use Symfony\Component\DependencyInjection\Reference; + .. code-block:: php - // Same as before - $definition = new Definition(); + // config/services.php + use App\Mail\GreetingCardManager; + use App\Mail\NewsletterManager; + use Symfony\Component\DependencyInjection\Definition; + use Symfony\Component\DependencyInjection\Reference; - $definition->setAutowired(true); + // Same as before + $definition = new Definition(); - $this->registerClasses($definition, 'App\\', '../src/*'); + $definition->setAutowired(true); - $container->getDefinition(NewsletterManager::class) - ->setConfigurator(new Reference(EmailConfigurator::class)); + $this->registerClasses($definition, 'App\\', '../src/*'); + + $container->getDefinition(NewsletterManager::class) + ->setConfigurator(new Reference(EmailConfigurator::class)); - $container->getDefinition(GreetingCardManager::class) - ->setConfigurator(new Reference(EmailConfigurator::class)); + $container->getDefinition(GreetingCardManager::class) + ->setConfigurator(new Reference(EmailConfigurator::class)); That's it! When requesting the ``App\Mail\NewsletterManager`` or ``App\Mail\GreetingCardManager`` service, the created instance will first be diff --git a/service_container/factories.rst b/service_container/factories.rst index e121f43aea9..3fc4a979336 100644 --- a/service_container/factories.rst +++ b/service_container/factories.rst @@ -202,14 +202,14 @@ method name, just as routes can reference + https://symfony.com/schema/dic/services/services-1.0.xsd"> - + From 6e0ff0bec8b8b5f5d998631b85f2ae1a2de61521 Mon Sep 17 00:00:00 2001 From: Hamza Amrouche Date: Fri, 12 Apr 2019 15:35:33 +0200 Subject: [PATCH 114/499] [PhpUnitBridge] ClockMock does not mock gmdate() --- 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 dec8e1cf10a..38892fe0599 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -325,7 +325,7 @@ Clock Mocking The :class:`Symfony\\Bridge\\PhpUnit\\ClockMock` class provided by this bridge allows you to mock the PHP's built-in time functions ``time()``, -``microtime()``, ``sleep()`` and ``usleep()``. Additionally the function +``microtime()``, ``sleep()``, ``usleep()`` and ``gmdate``. Additionally the function ``date()`` is mocked so it uses the mocked time if no timestamp is specified. Other functions with an optional timestamp parameter that defaults to ``time()`` will still use the system time instead of the mocked time. From 4bd7dbc68ee9dbc61f8370565dcc0e70f7455228 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 12 Apr 2019 16:45:08 +0200 Subject: [PATCH 115/499] Minor tweak --- 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 38892fe0599..b4f40f4c1c7 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -325,7 +325,7 @@ Clock Mocking The :class:`Symfony\\Bridge\\PhpUnit\\ClockMock` class provided by this bridge allows you to mock the PHP's built-in time functions ``time()``, -``microtime()``, ``sleep()``, ``usleep()`` and ``gmdate``. Additionally the function +``microtime()``, ``sleep()``, ``usleep()`` and ``gmdate()``. Additionally the function ``date()`` is mocked so it uses the mocked time if no timestamp is specified. Other functions with an optional timestamp parameter that defaults to ``time()`` will still use the system time instead of the mocked time. From f0ec0585957addb3990e636570deaf4785b091b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Sun, 14 Apr 2019 11:13:08 +0200 Subject: [PATCH 116/499] Fix typos --- mercure.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mercure.rst b/mercure.rst index 34d6ea6231c..d5699b3c5f2 100644 --- a/mercure.rst +++ b/mercure.rst @@ -115,7 +115,7 @@ publish: } Because the array is empty, the Symfony app will only be authorized to publish -public updates (see the authorization_ section for further informations). +public updates (see the authorization_ section for further information). .. tip:: From 7c04fd1212c5600126209810575a867a14ea8c95 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 12 Apr 2019 15:49:44 +0200 Subject: [PATCH 117/499] Documented the Inflector component --- components/inflector.rst | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 components/inflector.rst diff --git a/components/inflector.rst b/components/inflector.rst new file mode 100644 index 00000000000..5e9f4325884 --- /dev/null +++ b/components/inflector.rst @@ -0,0 +1,64 @@ +.. index:: + single: Inflector + single: Components; Inflector + +The Inflector Component +======================= + + The Inflector component converts English words between their singular and + plural forms. + +Installation +------------ + +.. code-block:: terminal + + $ composer require symfony/inflector + +.. include:: /components/require_autoload.rst.inc + +When you May Need an Inflector +------------------------------ + +In some scenarios such as code generation and code introspection, it's usually +required to convert words from/to singular/plural. For example, if you need to +know which property is associated with an *adder* method, you must convert from +plural to singular (``addStories()`` method -> ``$story`` property). + +Although most human languages define simple pluralization rules, they also +define lots of exceptions. For example, the general rule in English is to add an +``s`` at the end of the word (``book`` -> ``books``) but there are lots of +exceptions even for common words (``woman`` -> ``women``, ``life`` -> ``lives``, +``news`` -> ``news``, ``radius`` -> ``radii``, etc.) + +This component abstracts all those pluralization rules so you can convert +from/to singular/plural with confidence. However, due to the complexity of the +human languages, this component only provides support for the English language. + +Usage +----- + +The Inflector component provides two static methods to convert from/to +singular/plural:: + + use Symfony\Component\Inflector\Inflector; + + Inflector::singularize('alumni'); // 'alumnus' + Inflector::singularize('knives'); // 'knife' + Inflector::singularize('mice'); // 'mouse' + + Inflector::pluralize('grandchild'); // 'grandchildren' + Inflector::pluralize('news'); // 'news' + Inflector::pluralize('bacterium'); // 'bacteria' + +Sometimes it's not possible to determine a unique singular/plural form for the +given word. In those cases, the methods return an array with all the possible +forms:: + + use Symfony\Component\Inflector\Inflector; + + Inflector::singularize('indices'); // ['index', 'indix', 'indice'] + Inflector::singularize('leaves'); // ['leaf', 'leave', 'leaff'] + + Inflector::pluralize('matrix'); // ['matricies', 'matrixes'] + Inflector::pluralize('person'); // ['persons', 'people'] From 5325b151b670a1d8b8fdafd33a173e584f26ecae Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 16 Apr 2019 11:22:13 +0200 Subject: [PATCH 118/499] Documented the new Intl classes --- components/intl.rst | 118 +++++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 45 deletions(-) diff --git a/components/intl.rst b/components/intl.rst index 00cbd65cd79..9508f50dec5 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -209,125 +209,152 @@ locale will be merged. In order to suppress this behavior, the last parameter Accessing ICU Data ------------------ -The ICU data is located in several "resource bundles". You can access a PHP -wrapper of these bundles through the static -:class:`Symfony\\Component\\Intl\\Intl` class. At the moment, the following -data is supported: +This component provides the following ICU data: * `Language and Script Names`_ -* `Country Names`_ +* `Country and Region Names`_ * `Locales`_ * `Currencies`_ Language and Script Names ~~~~~~~~~~~~~~~~~~~~~~~~~ -The translations of language and script names can be found in the language -bundle:: +The ``Languages`` class provides access to the name of all languages:: - use Symfony\Component\Intl\Intl; + use Symfony\Component\Intl\Languages; \Locale::setDefault('en'); - $languages = Intl::getLanguageBundle()->getLanguageNames(); + $languages = Languages::getNames(); // => ['ab' => 'Abkhazian', ...] - $language = Intl::getLanguageBundle()->getLanguageName('de'); + $language = Languages::getName('de'); // => 'German' - $language = Intl::getLanguageBundle()->getLanguageName('de', 'AT'); + $language = Languages::getName('de', 'AT'); // => 'Austrian German' - $scripts = Intl::getLanguageBundle()->getScriptNames(); +All methods accept the translation locale as the last, optional parameter, +which defaults to the current default locale:: + + $languages = Languages::getNames('de'); + // => ['ab' => 'Abchasisch', ...] + +.. 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`` +for traditional Chinese):: + + use Symfony\Component\Intl\Scripts; + + \Locale::setDefault('en'); + + $scripts = Scripts::getNames(); // => ['Arab' => 'Arabic', ...] - $script = Intl::getLanguageBundle()->getScriptName('Hans'); + $script = Scripts::getName('Hans'); // => 'Simplified' -All methods accept the translation locale as the last, optional parameter, -which defaults to the current default locale:: +.. versionadded:: 4.3 - $languages = Intl::getLanguageBundle()->getLanguageNames('de'); - // => ['ab' => 'Abchasisch', ...] + The ``Scrcipts`` class was introduced in Symfony 4.3. + +.. _country-names: -Country Names -~~~~~~~~~~~~~ +Country and Region Names +~~~~~~~~~~~~~~~~~~~~~~~~ -The translations of country names can be found in the region bundle:: +In the world there are some territorial disputes that make it hard to define +what a country is. That's why the Intl component provides a ``Regions`` class +instead of a ``Countries`` class:: - use Symfony\Component\Intl\Intl; + use Symfony\Component\Intl\Regions; \Locale::setDefault('en'); - $countries = Intl::getRegionBundle()->getCountryNames(); + $countries = Regions::getNames(); // => ['AF' => 'Afghanistan', ...] - $country = Intl::getRegionBundle()->getCountryName('GB'); + $country = Regions::getName('GB'); // => 'United Kingdom' All methods accept the translation locale as the last, optional parameter, which defaults to the current default locale:: - $countries = Intl::getRegionBundle()->getCountryNames('de'); + $countries = Regions::getNames('de'); // => ['AF' => 'Afghanistan', ...] +.. versionadded:: 4.3 + + The ``Regions`` class was introduced in Symfony 4.3. + Locales ~~~~~~~ -The translations of locale names can be found in the locale bundle:: +A locale is the combination of a language and a region. 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\Intl; + use Symfony\Component\Intl\Locales; \Locale::setDefault('en'); - $locales = Intl::getLocaleBundle()->getLocaleNames(); + $locales = Locales::getNames(); // => ['af' => 'Afrikaans', ...] - $locale = Intl::getLocaleBundle()->getLocaleName('zh_Hans_MO'); + $locale = Locales::getName('zh_Hans_MO'); // => 'Chinese (Simplified, Macau SAR China)' All methods accept the translation locale as the last, optional parameter, which defaults to the current default locale:: - $locales = Intl::getLocaleBundle()->getLocaleNames('de'); + $locales = Locales::getNames('de'); // => ['af' => 'Afrikaans', ...] +.. versionadded:: 4.3 + + The ``Locales`` class was introduced in Symfony 4.3. + Currencies ~~~~~~~~~~ -The translations of currency names and other currency-related information can -be found in the currency bundle:: +The ``Currencies`` class provides access to the name of all currencies as well +as some of their information (symbol, fraction digits, etc.):: - use Symfony\Component\Intl\Intl; + use Symfony\Component\Intl\Currencies; \Locale::setDefault('en'); - $currencies = Intl::getCurrencyBundle()->getCurrencyNames(); + $currencies = Currencies::getNames(); // => ['AFN' => 'Afghan Afghani', ...] - $currency = Intl::getCurrencyBundle()->getCurrencyName('INR'); + $currency = Currencies::getName('INR'); // => 'Indian Rupee' - $symbol = Intl::getCurrencyBundle()->getCurrencySymbol('INR'); + $symbol = Currencies::getSymbol('INR'); // => '₹' - $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits('INR'); + $fractionDigits = Currencies::getFractionDigits('INR'); // => 2 - $roundingIncrement = Intl::getCurrencyBundle()->getRoundingIncrement('INR'); + $roundingIncrement = Currencies::getRoundingIncrement('INR'); // => 0 -All methods (except for -:method:`Symfony\\Component\\Intl\\ResourceBundle\\CurrencyBundleInterface::getFractionDigits` -and -:method:`Symfony\\Component\\Intl\\ResourceBundle\\CurrencyBundleInterface::getRoundingIncrement`) -accept the translation locale as the last, optional parameter, which defaults -to the current default locale:: +All methods (except for ``getFractionDigits()`` and ``getRoundingIncrement()``) +accept the translation locale as the last, optional parameter, which defaults to +the current default locale:: - $currencies = Intl::getCurrencyBundle()->getCurrencyNames('de'); + $currencies = Currencies::getNames('de'); // => ['AFN' => 'Afghanische Afghani', ...] -That's all you need to know for now. Have fun coding! +.. versionadded:: 4.3 + + The ``Currencies`` class was introduced in Symfony 4.3. Learn more ---------- @@ -346,3 +373,4 @@ Learn more .. _intl extension: https://php.net/manual/en/book.intl.php .. _install the intl extension: https://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 1ef964e0ee16d10d17aaf1738810ab88ca97b776 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 17 Apr 2019 16:24:18 +0200 Subject: [PATCH 119/499] Document the new Intl exists() methods --- components/intl.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/components/intl.rst b/components/intl.rst index 9508f50dec5..707a2ccc4f2 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -240,6 +240,10 @@ which defaults to the current default locale:: $languages = Languages::getNames('de'); // => ['ab' => 'Abchasisch', ...] +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. @@ -259,6 +263,10 @@ for traditional Chinese):: $script = Scripts::getName('Hans'); // => 'Simplified' +You can also check if a given script code is valid:: + + $isValidScript = Scripts::exists($scriptCode); + .. versionadded:: 4.3 The ``Scrcipts`` class was introduced in Symfony 4.3. @@ -288,6 +296,10 @@ which defaults to the current default locale:: $countries = Regions::getNames('de'); // => ['AF' => 'Afghanistan', ...] +You can also check if a given region code is valid:: + + $isValidRegion = Regions::exists($regionCode); + .. versionadded:: 4.3 The ``Regions`` class was introduced in Symfony 4.3. @@ -316,6 +328,10 @@ which defaults to the current default locale:: $locales = Locales::getNames('de'); // => ['af' => 'Afrikaans', ...] +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. @@ -352,6 +368,10 @@ the current default locale:: $currencies = Currencies::getNames('de'); // => ['AFN' => 'Afghanische Afghani', ...] +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. From d625ac5dd40dbafa155471b26e5ef7cf7a447f04 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza Date: Mon, 22 Apr 2019 08:26:47 +0200 Subject: [PATCH 120/499] feature: move hinclude from template to fragments --- reference/configuration/framework.rst | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 4bd247ba978..e5ee77a50b7 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -608,6 +608,19 @@ path The path prefix for fragments. The fragment listener will only be executed when the request starts with this path. +hinclude_default_template +......................... + +**type**: ``string`` **default**: ``null`` + +Sets the content shown during the loading of the fragment or when JavaScript +is disabled. This can be either a template name or the content itself. + +.. seealso:: + + See :doc:`/templating/hinclude` for more information about hinclude. + + profiler ~~~~~~~~ @@ -1537,18 +1550,6 @@ package: templating ~~~~~~~~~~ -hinclude_default_template -......................... - -**type**: ``string`` **default**: ``null`` - -Sets the content shown during the loading of the fragment or when JavaScript -is disabled. This can be either a template name or the content itself. - -.. seealso:: - - See :doc:`/templating/hinclude` for more information about hinclude. - .. _reference-templating-form: form From 8d9d7b52ed9a3863e80c5b59590ca2f67a3dd4e4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 17 Apr 2019 09:20:29 +0200 Subject: [PATCH 121/499] Updated Argon2i encoder by Sodium encoder --- best_practices/security.rst | 2 +- reference/configuration/security.rst | 45 +++++++++++++++++----------- security.rst | 4 +-- security/named_encoders.rst | 2 +- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/best_practices/security.rst b/best_practices/security.rst index f746303d347..524b8866b72 100644 --- a/best_practices/security.rst +++ b/best_practices/security.rst @@ -39,7 +39,7 @@ remain resistant to brute-force search attacks. .. note:: - :ref:`Argon2i ` is the hashing algorithm as + :ref:`Sodium ` is the hashing algorithm as recommended by industry standards, but this won't be available to you unless you are using PHP 7.2+ or have the `libsodium`_ extension installed. ``bcrypt`` is sufficient for most applications. diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 341a94495f2..d25e415d83a 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -137,12 +137,12 @@ encoding algorithm. Also, each algorithm defines different config options: algorithm: 'bcrypt' cost: 15 - # Argon2i encoder with default options - App\Entity\User: 'argon2i' + # Sodium encoder with default options + App\Entity\User: 'sodium' - # Argon2i encoder with custom options + # Sodium encoder with custom options App\Entity\User: - algorithm: 'argon2i' + algorithm: 'sodium' memory_cost: 16384 # Amount in KiB. (16384 = 16 MiB) time_cost: 2 # Number of iterations threads: 4 # Number of parallel threads @@ -175,19 +175,19 @@ encoding algorithm. Also, each algorithm defines different config options: cost="15" /> - + - + 15, ], - // Argon2i encoder with default options + // Sodium encoder with default options User::class => [ - 'algorithm' => 'argon2i', + 'algorithm' => 'sodium', ], - // Argon2i encoder with custom options + // Sodium encoder with custom options User::class => [ - 'algorithm' => 'argon2i', + 'algorithm' => 'sodium', 'memory_cost' => 16384, // Amount in KiB. (16384 = 16 MiB) 'time_cost' => 2, // Number of iterations 'threads' => 4, // Number of parallel threads @@ -240,16 +240,27 @@ encoding algorithm. Also, each algorithm defines different config options: ], ]); +.. 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 select a different password encoder for each user instance. Read :doc:`this article ` for more details. -.. _reference-security-argon2i: +.. _reference-security-sodium: +.. _using-the-argon2i-password-encoder: + +Using the Sodium Password Encoder +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 4.3 -Using the Argon2i Password Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 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 @@ -267,7 +278,7 @@ Using the BCrypt Password Encoder ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It uses the `bcrypt password hashing function`_ and it's recommended to use it -when it's not possible to use Argon2i. The encoded passwords are ``60`` +when it's not possible to use Sodium. The encoded 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. @@ -294,7 +305,7 @@ Using the PBKDF2 Encoder ~~~~~~~~~~~~~~~~~~~~~~~~ Using the `PBKDF2`_ encoder is no longer recommended since PHP added support for -Argon2i and bcrypt. Legacy application still using it are encouraged to upgrade +Sodium and bcrypt. Legacy application still using it are encouraged to upgrade to those newer encoding algorithms. firewalls diff --git a/security.rst b/security.rst index 0ca69ce403a..81369650310 100644 --- a/security.rst +++ b/security.rst @@ -124,8 +124,8 @@ command will pre-configure this for you: encoders: # use your user class name here App\Entity\User: - # bcrypt or argon2i are recommended - # argon2i is more secure, but requires PHP 7.2 or the Sodium extension + # bcrypt or sodium are recommended + # sodium is more secure, but requires PHP 7.2 or the Sodium extension algorithm: bcrypt cost: 12 diff --git a/security/named_encoders.rst b/security/named_encoders.rst index fbf57fe8dce..8f47feefabc 100644 --- a/security/named_encoders.rst +++ b/security/named_encoders.rst @@ -109,7 +109,7 @@ be done with named encoders: If you are running PHP 7.2+ or have the `libsodium`_ extension installed, then the recommended hashing algorithm to use is - :ref:`Argon2i `. + :ref:`Sodium `. This creates an encoder named ``harsh``. In order for a ``User`` instance to use it, the class must implement From 422ff6bce2393a20248835eafb401d565f81939b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 23 Apr 2019 10:29:50 +0200 Subject: [PATCH 122/499] Minor tweaks --- reference/configuration/framework.rst | 29 ++++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index e5ee77a50b7..95890c86aa6 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -85,6 +85,7 @@ Configuration * `fragments`_ * :ref:`enabled ` + * `hinclude_default_template`_ * :ref:`path ` * `http_method_override`_ @@ -167,7 +168,6 @@ Configuration * `resources`_ - * `hinclude_default_template`_ * `loaders`_ * `test`_ @@ -353,7 +353,7 @@ need to escape the percent signs (``%``) by doubling them. // as /path/to/host/.../file on the host // and /var/www/app/ as /projects/my_project/ also 'myide://%%f:%%l&/path/to/guest/>/path/to/host/&/var/www/app/>/projects/my_project/&...' - + // example for PhpStorm 'phpstorm://open?file=%%f&line=%%l&/var/www/app/>/projects/my_project/' @@ -598,21 +598,17 @@ used to render ESI fragments independently of the rest of the page. This setting is automatically set to ``true`` when one of the child settings is configured. -.. _reference-fragments-path: - -path -.... - -**type**: ``string`` **default**: ``'/_fragment'`` - -The path prefix for fragments. The fragment listener will only be executed -when the request starts with this path. - hinclude_default_template ......................... **type**: ``string`` **default**: ``null`` +.. versionadded:: 4.3 + + The ``framework.fragments.hinclude_default_template`` option was introduced + in Symfony 4.3. In previous Symfony versions it was defined under + ``framework.templating.hinclude_default_template``. + Sets the content shown during the loading of the fragment or when JavaScript is disabled. This can be either a template name or the content itself. @@ -620,6 +616,15 @@ is disabled. This can be either a template name or the content itself. See :doc:`/templating/hinclude` for more information about hinclude. +.. _reference-fragments-path: + +path +.... + +**type**: ``string`` **default**: ``'/_fragment'`` + +The path prefix for fragments. The fragment listener will only be executed +when the request starts with this path. profiler ~~~~~~~~ From 004fe74ea6fd9d8a603dfe601199a721e663d3e0 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 23 Apr 2019 16:09:59 +0200 Subject: [PATCH 123/499] Improved the Intl component docs --- components/intl.rst | 53 ++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/components/intl.rst b/components/intl.rst index 707a2ccc4f2..f995b053d1f 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -226,19 +226,20 @@ The ``Languages`` class provides access to the name of all languages:: \Locale::setDefault('en'); $languages = Languages::getNames(); - // => ['ab' => 'Abkhazian', ...] + // ('languageCode' => 'languageName') + // => ['ab' => 'Abkhazian', 'ace' => 'Achinese', ...] - $language = Languages::getName('de'); - // => 'German' - - $language = Languages::getName('de', 'AT'); - // => 'Austrian German' + $language = Languages::getName('fr'); + // => 'French' All methods accept the translation locale as the last, optional parameter, which defaults to the current default locale:: $languages = Languages::getNames('de'); - // => ['ab' => 'Abchasisch', ...] + // => ['ab' => 'Abchasisch', 'ace' => 'Aceh', ...] + + $language = Languages::getName('fr', 'de'); + // => 'Französisch' You can also check if a given language code is valid:: @@ -258,18 +259,28 @@ for traditional Chinese):: \Locale::setDefault('en'); $scripts = Scripts::getNames(); - // => ['Arab' => 'Arabic', ...] + // ('scriptCode' => 'scriptName') + // => ['Adlm' => 'Adlam', 'Afak' => 'Afaka', ...] $script = Scripts::getName('Hans'); // => 'Simplified' +All methods accept the translation locale as the last, optional parameter, +which defaults to the current default locale:: + + $languages = Scripts::getNames('de'); + // => ['Adlm' => 'Adlam', 'Afak' => 'Afaka', ...] + + $language = Scripts::getName('Hans', 'de'); + // => 'Vereinfacht' + You can also check if a given script code is valid:: $isValidScript = Scripts::exists($scriptCode); .. versionadded:: 4.3 - The ``Scrcipts`` class was introduced in Symfony 4.3. + The ``Scripts`` class was introduced in Symfony 4.3. .. _country-names: @@ -285,7 +296,8 @@ instead of a ``Countries`` class:: \Locale::setDefault('en'); $countries = Regions::getNames(); - // => ['AF' => 'Afghanistan', ...] + // ('regionCode' => 'regionName') + // => ['AF' => 'Afghanistan', 'AX' => 'Åland Islands', ...] $country = Regions::getName('GB'); // => 'United Kingdom' @@ -294,7 +306,10 @@ All methods accept the translation locale as the last, optional parameter, which defaults to the current default locale:: $countries = Regions::getNames('de'); - // => ['AF' => 'Afghanistan', ...] + // => ['AF' => 'Afghanistan', 'EG' => 'Ägypten', ...] + + $country = Regions::getName('GB', 'de'); + // => 'Vereinigtes Königreich' You can also check if a given region code is valid:: @@ -317,7 +332,8 @@ provides access to the name of all locales:: \Locale::setDefault('en'); $locales = Locales::getNames(); - // => ['af' => 'Afrikaans', ...] + // ('localeCode' => 'localeName') + // => ['af' => 'Afrikaans', 'af_NA' => 'Afrikaans (Namibia)', ...] $locale = Locales::getName('zh_Hans_MO'); // => 'Chinese (Simplified, Macau SAR China)' @@ -326,7 +342,10 @@ All methods accept the translation locale as the last, optional parameter, which defaults to the current default locale:: $locales = Locales::getNames('de'); - // => ['af' => 'Afrikaans', ...] + // => ['af' => 'Afrikaans', 'af_NA' => 'Afrikaans (Namibia)', ...] + + $locale = Locales::getName('zh_Hans_MO', 'de'); + // => 'Chinesisch (Vereinfacht, Sonderverwaltungsregion Macau)' You can also check if a given locale code is valid:: @@ -347,7 +366,8 @@ as some of their information (symbol, fraction digits, etc.):: \Locale::setDefault('en'); $currencies = Currencies::getNames(); - // => ['AFN' => 'Afghan Afghani', ...] + // ('currencyCode' => 'currencyName') + // => ['AFN' => 'Afghan Afghani', 'ALL' => 'Albanian Lek', ...] $currency = Currencies::getName('INR'); // => 'Indian Rupee' @@ -366,7 +386,10 @@ accept the translation locale as the last, optional parameter, which defaults to the current default locale:: $currencies = Currencies::getNames('de'); - // => ['AFN' => 'Afghanische Afghani', ...] + // => ['AFN' => 'Afghanischer Afghani', 'EGP' => 'Ägyptisches Pfund', ...] + + $currency = Currencies::getName('INR', 'de'); + // => 'Indische Rupie' You can also check if a given currency code is valid:: From 9a201fb650efbf96bea5f73b7eb958466790758f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 23 Apr 2019 15:49:38 +0200 Subject: [PATCH 124/499] Documented the Timezones Intl bundle --- components/intl.rst | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/components/intl.rst b/components/intl.rst index 707a2ccc4f2..05732856e5d 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -215,6 +215,7 @@ This component provides the following ICU data: * `Country and Region Names`_ * `Locales`_ * `Currencies`_ +* `Timezones`_ Language and Script Names ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -376,6 +377,39 @@ You can also check if a given currency code is valid:: The ``Currencies`` class was introduced in Symfony 4.3. +Timezones +~~~~~~~~~ + +The ``Timezones`` class provides access to the name and values of all timezones:: + + use Symfony\Component\Intl\Timezones; + + \Locale::setDefault('en'); + + $timezones = Timezones::getNames(); + // ('timezoneName' => 'timezoneValue') + // => ['America/Eirunepe' => 'Acre Time (Eirunepe)', 'America/Rio_Branco' => 'Acre Time (Rio Branco)', ...] + + $timezone = Timezones::getName('Africa/Nairobi'); + // => 'East Africa Time (Nairobi)' + +All methods accept the translation locale as the last, optional parameter, +which defaults to the current default locale:: + + $timezones = Timezones::getNames('de'); + // => ['America/Eirunepe' => 'Acre-Zeit (Eirunepe)', 'America/Rio_Branco' => 'Acre-Zeit (Rio Branco)', ...] + + $timezone = Timezones::getName('Africa/Nairobi', 'de'); + // => 'Ostafrikanische Zeit (Nairobi)' + +You can also check if a given timezone name is valid:: + + $isValidTimezone = Timezones::exists($timezoneName); + +.. versionadded:: 4.3 + + The ``Timezones`` class was introduced in Symfony 4.3. + Learn more ---------- From ca9db00643410845e8078f879251eb3789825263 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 24 Apr 2019 12:54:41 +0200 Subject: [PATCH 125/499] Timezone "name" should be renamed to timezone "ID" --- components/intl.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/intl.rst b/components/intl.rst index 462ea11c587..43b7c77425a 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -410,7 +410,7 @@ The ``Timezones`` class provides access to the name and values of all timezones: \Locale::setDefault('en'); $timezones = Timezones::getNames(); - // ('timezoneName' => 'timezoneValue') + // ('timezoneID' => 'timezoneValue') // => ['America/Eirunepe' => 'Acre Time (Eirunepe)', 'America/Rio_Branco' => 'Acre Time (Rio Branco)', ...] $timezone = Timezones::getName('Africa/Nairobi'); @@ -425,9 +425,9 @@ which defaults to the current default locale:: $timezone = Timezones::getName('Africa/Nairobi', 'de'); // => 'Ostafrikanische Zeit (Nairobi)' -You can also check if a given timezone name is valid:: +You can also check if a given timezone ID is valid:: - $isValidTimezone = Timezones::exists($timezoneName); + $isValidTimezone = Timezones::exists($timezoneId); .. versionadded:: 4.3 From 9d34ea08aef9bf60169a4375b967cf301d8e8ee0 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 24 Apr 2019 17:36:08 +0200 Subject: [PATCH 126/499] Minor reword --- reference/constraints/Email.rst | 1 + reference/constraints/Ip.rst | 1 + reference/constraints/Length.rst | 1 + reference/constraints/NotBlank.rst | 11 +---------- reference/constraints/Regex.rst | 1 + reference/constraints/Url.rst | 1 + reference/constraints/Uuid.rst | 1 + reference/constraints/_normalizer-option.rst.inc | 13 ++++++++----- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/reference/constraints/Email.rst b/reference/constraints/Email.rst index a50f25189b9..8b68f59bea2 100644 --- a/reference/constraints/Email.rst +++ b/reference/constraints/Email.rst @@ -169,6 +169,7 @@ html5 This matches the pattern used for the `HTML5 email input element`_. .. include:: /reference/constraints/_normalizer-option.rst.inc + .. include:: /reference/constraints/_payload-option.rst.inc .. _egulias/email-validator: https://packagist.org/packages/egulias/email-validator diff --git a/reference/constraints/Ip.rst b/reference/constraints/Ip.rst index daef85dd878..60865c024bc 100644 --- a/reference/constraints/Ip.rst +++ b/reference/constraints/Ip.rst @@ -98,6 +98,7 @@ Parameter Description =============== ============================================================== .. include:: /reference/constraints/_normalizer-option.rst.inc + .. include:: /reference/constraints/_payload-option.rst.inc version diff --git a/reference/constraints/Length.rst b/reference/constraints/Length.rst index 96ccc721b41..88ef1040b70 100644 --- a/reference/constraints/Length.rst +++ b/reference/constraints/Length.rst @@ -214,4 +214,5 @@ Parameter Description ================= ============================================================ .. include:: /reference/constraints/_normalizer-option.rst.inc + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/NotBlank.rst b/reference/constraints/NotBlank.rst index 3fe69bf7cdf..83b2713d225 100644 --- a/reference/constraints/NotBlank.rst +++ b/reference/constraints/NotBlank.rst @@ -111,15 +111,6 @@ Parameter Description ``{{ value }}`` The current (invalid) value =============== ============================================================== -normalizer -~~~~~~~~~~ - -**type**: ``string`` **default**: ``null`` - -If the given value is a ``string``, this option can be used to normalize it while -checking if it is valid. A ``callable`` must be passed. - -For example, you may want to use :phpfunction:`trim` to ignore leading and -trailing whitespace during validation. +.. include:: /reference/constraints/_normalizer-option.rst.inc .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Regex.rst b/reference/constraints/Regex.rst index 858026f1d1c..d7e3c8f2ebd 100644 --- a/reference/constraints/Regex.rst +++ b/reference/constraints/Regex.rst @@ -289,4 +289,5 @@ PHP function). However, if `match`_ is set to false, then validation will fail if the input string *does* match this pattern. .. include:: /reference/constraints/_normalizer-option.rst.inc + .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Url.rst b/reference/constraints/Url.rst index 26951e0e588..4c9885d0147 100644 --- a/reference/constraints/Url.rst +++ b/reference/constraints/Url.rst @@ -321,6 +321,7 @@ Parameter Description } .. include:: /reference/constraints/_normalizer-option.rst.inc + .. include:: /reference/constraints/_payload-option.rst.inc protocols diff --git a/reference/constraints/Uuid.rst b/reference/constraints/Uuid.rst index 4dd488708fc..aad14472dfe 100644 --- a/reference/constraints/Uuid.rst +++ b/reference/constraints/Uuid.rst @@ -100,6 +100,7 @@ Parameter Description =============== ============================================================== .. include:: /reference/constraints/_normalizer-option.rst.inc + .. include:: /reference/constraints/_payload-option.rst.inc strict diff --git a/reference/constraints/_normalizer-option.rst.inc b/reference/constraints/_normalizer-option.rst.inc index 262d7e41177..784f915ff95 100644 --- a/reference/constraints/_normalizer-option.rst.inc +++ b/reference/constraints/_normalizer-option.rst.inc @@ -1,10 +1,13 @@ normalizer ~~~~~~~~~~ -**type**: ``string`` **default**: ``null`` +**type**: a `PHP callable`_ **default**: ``null`` -This option allows a ``callable`` to be passed in order to normalize the given -value while checking if it is valid. +This option allows to define the PHP callable applied to the given value before +checking if it is valid. -For example, you may want to use :phpfunction:`trim` to ignore leading and -trailing whitespace during validation. +For example, you may want to pass the ``'trim'`` string to apply the +:phpfunction:`trim` PHP function in order to ignore leading and trailing +whitespace during validation. + +.. _`PHP callable`: https://www.php.net/callable From 6d8390cba88656298d5fd2abbf9ad9928207d82a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 24 Apr 2019 18:31:14 +0200 Subject: [PATCH 127/499] [Cache] Update for 4.3 --- components/cache/psr6_psr16_adapters.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/components/cache/psr6_psr16_adapters.rst b/components/cache/psr6_psr16_adapters.rst index 4dc676e8b9c..b110c5dab3b 100644 --- a/components/cache/psr6_psr16_adapters.rst +++ b/components/cache/psr6_psr16_adapters.rst @@ -11,6 +11,10 @@ standard, but need to pass it to an object that expects a :ref:`PSR-6 Date: Thu, 25 Apr 2019 09:10:14 +0200 Subject: [PATCH 128/499] Fixed more wrong white spaces --- components/mime.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/mime.rst b/components/mime.rst index 62bb707ebdb..085145f5abc 100644 --- a/components/mime.rst +++ b/components/mime.rst @@ -198,10 +198,10 @@ the following tree is the one that works on most email clients: multipart/mixed ├── multipart/related - │   ├── multipart/alternative - │   │   ├── text/plain - │   │   └── text/html - │   └── image/png + │ ├── multipart/alternative + │ │ ├── text/plain + │ │ └── text/html + │ └── image/png └── application/pdf This is the purpose of each MIME message part: From 7402bfbaf61fb95e9049772f3b7f67ae80ce9338 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 25 Apr 2019 09:07:07 -0400 Subject: [PATCH 129/499] minor tweak --- components/cache/psr6_psr16_adapters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/cache/psr6_psr16_adapters.rst b/components/cache/psr6_psr16_adapters.rst index b110c5dab3b..5bf355d5e93 100644 --- a/components/cache/psr6_psr16_adapters.rst +++ b/components/cache/psr6_psr16_adapters.rst @@ -13,7 +13,7 @@ two classes for bidirectional interoperability between PSR-6 and PSR-16 caches. .. versionadded:: 4.3 - The ``Psr16Adapter`` and ``Psr16Cache`` classes mentionned below were added in Symfony 4.3. + The ``Psr16Adapter`` and ``Psr16Cache`` classes mentioned below were added in Symfony 4.3. Using a PSR-16 Cache Object as a PSR-6 Cache -------------------------------------------- From 8112be5caccee247d681beccaab329083dbb0c91 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 25 Apr 2019 15:33:59 +0200 Subject: [PATCH 130/499] Reworded the versionadded directives --- components/cache/psr6_psr16_adapters.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/cache/psr6_psr16_adapters.rst b/components/cache/psr6_psr16_adapters.rst index 5bf355d5e93..96e29a6d8ea 100644 --- a/components/cache/psr6_psr16_adapters.rst +++ b/components/cache/psr6_psr16_adapters.rst @@ -11,10 +11,6 @@ standard, but need to pass it to an object that expects a :ref:`PSR-6 Date: Thu, 18 Apr 2019 06:56:14 +0200 Subject: [PATCH 131/499] [Security] Dispatch an event when "logout user on change" steps in --- components/security/authentication.rst | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/components/security/authentication.rst b/components/security/authentication.rst index ee4e99b6529..d7516286d0f 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -276,14 +276,15 @@ Authentication Events The security component provides 4 related authentication events: -=============================== ================================================ ============================================================================== -Name Event Constant Argument Passed to the Listener -=============================== ================================================ ============================================================================== -security.authentication.success ``AuthenticationEvents::AUTHENTICATION_SUCCESS`` :class:`Symfony\\Component\\Security\\Core\\Event\\AuthenticationEvent` -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` -=============================== ================================================ ============================================================================== +=============================== ================================================================= ============================================================================== +Name Event Constant Argument Passed to the Listener +=============================== ================================================================= ============================================================================== +security.authentication.success ``AuthenticationEvents::AUTHENTICATION_SUCCESS`` :class:`Symfony\\Component\\Security\\Core\\Event\\AuthenticationEvent` +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:`Symfony\Component\Security\Http\EventDeauthenticatedEvent` +=============================== ================================================================= ============================================================================== Authentication Success and Failure Events ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -314,6 +315,13 @@ 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 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 From 0390bad0204dacdf44b1313c157e11fc7c5a2118 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 1 Mar 2019 11:26:34 +0100 Subject: [PATCH 132/499] Documented the new HttpClient component --- components/http_client.rst | 537 ++++++++++++++++++++++++++ reference/configuration/framework.rst | 294 ++++++++++++++ 2 files changed, 831 insertions(+) create mode 100644 components/http_client.rst diff --git a/components/http_client.rst b/components/http_client.rst new file mode 100644 index 00000000000..2a99653a1ed --- /dev/null +++ b/components/http_client.rst @@ -0,0 +1,537 @@ +.. index:: + single: HttpClient + single: Components; HttpClient + +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 +------------ + +.. code-block:: terminal + + $ composer require symfony/http-client + +.. include:: /components/require_autoload.rst.inc + +Basic Usage +----------- + +Use the :class:`Symfony\\Component\\HttpClient\\HttpClient` class to create the +low-level HTTP client that makes requests, like the following ``GET`` request:: + + use Symfony\Component\HttpClient\HttpClient; + + $httpClient = HttpClient::create(); + $response = $httpClient->request('GET', 'https://api.github.com/repos/symfony/symfony-docs'); + + $statusCode = $response->getStatusCode(); + // $statusCode = 200 + $contentType = $response->getHeaders()['content-type'][0]; + // $contentType = 'application/json' + $content = $response->getContent(); + // $content = '{"id":521583, "name":"symfony-docs", ...}' + $content = $response->toArray(); + // $content = ['id' => 521583, 'name' => 'symfony-docs', ...] + +Enabling cURL Support +--------------------- + +This component supports both the native PHP streams and cURL to make the HTTP +requests. Although both are interchangeable and provide the same features, +including concurrent requests, HTTP/2 is only supported when using cURL. + +``HttpClient::create()`` selects the cURL transport if the `cURL PHP extension`_ +is enabled and falls back to PHP streams otherwise. If you prefer to select +the transport explicitly, use the following classes to create the client:: + + use Symfony\Component\HttpClient\NativeHttpClient; + use Symfony\Component\HttpClient\CurlHttpClient; + + // uses native PHP streams + $httpClient = new NativeHttpClient(); + + // uses the cURL PHP extension + $httpClient = new CurlHttpClient(); + +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. + +Enabling HTTP/2 Support +----------------------- + +HTTP/2 is only supported when using the cURL-based transport and the libcurl +version is >= 7.36.0. If you meet these requirements, you can enable HTTP/2 +explicitly via the ``http_version`` option:: + + $httpClient = HttpClient::create(['http_version' => '2.0']); + +If you don't set the HTTP version explicitly, Symfony will use ``'2.0'`` only +when the request protocol is ``https://`` (and the cURL requirements mentioned +earlier are met). + +Making Requests +--------------- + +The client created with the ``HttpClient`` class provides a single ``request()`` +method to perform all kinds of HTTP requests:: + + $response = $httpClient->request('GET', 'https://...'); + $response = $httpClient->request('POST', 'https://...'); + $response = $httpClient->request('PUT', 'https://...'); + // ... + +Responses are always asynchronous, so they are ready as soon as the response +HTTP headers are received, instead of waiting to receive the entire response +contents:: + + $response = $httpClient->request('GET', 'http://releases.ubuntu.com/18.04.2/ubuntu-18.04.2-desktop-amd64.iso'); + + // code execution continues immediately; it doesn't wait to receive the response + // you can get the value of any HTTP response header + $contentType = $response->getHeaders()['content-type'][0]; + + // trying to get the response contents will block the execution until + // the full response contents are received + $contents = $response->getContent(); + +This component also supports :ref:`streaming responses ` +for full asynchronous applications. + +Authentication +~~~~~~~~~~~~~~ + +The HTTP client supports different authentication mechanisms. They can be +defined globally when creating the client (to apply it to all requests) and to +each request (which overrides any global authentication):: + + // Use the same authentication for all requests + $httpClient = HttpClient::create([ + // HTTP Basic authentication with only the username and not a password + 'auth_basic' => ['the-username'], + + // HTTP Basic authentication with a username and a password + 'auth_basic' => ['the-username', 'the-password'], + + // HTTP Bearer authentication (also called token authentication) + 'auth_bearer' => 'the-bearer-token', + ]); + + $response = $httpClient->request('GET', 'https://...', [ + // use a different HTTP Basic authentication only for this request + 'auth_basic' => ['the-username', 'the-password'], + + // ... + ]); + +Query String Parameters +~~~~~~~~~~~~~~~~~~~~~~~ + +You can either append them manually to the requested URL, or better, add them +as an associative array to the ``query`` option:: + + // it makes an HTTP GET request to https://httpbin.org/get?token=...&name=... + $response = $httpClient->request('GET', 'https://httpbin.org/get', [ + // these values are automatically encoded before including them in the URL + 'query' => [ + 'token' => '...', + 'name' => '...', + ], + ]); + +Headers +~~~~~~~ + +Use the ``headers`` option to define both the default headers added to all +requests and the specific headers for each request:: + + // this header is added to all requests made by this client + $httpClient = HttpClient::create(['headers' => [ + 'Accept-Encoding' => 'gzip', + ]]); + + // this header is only included in this request and overrides the value + // of the same header if defined globally by the HTTP client + $response = $httpClient->request('POST', 'https://...', [ + 'headers' => [ + 'Content-Type' => 'text/plain', + ], + ]); + +Uploading Data +~~~~~~~~~~~~~~ + +This component provides several methods for uploading data using the ``body`` +option. You can use regular strings, closures and resources and they'll be +processed automatically when making the requests:: + + $response = $httpClient->request('POST', 'https://...', [ + // defining data using a regular string + 'body' => 'raw data', + + // defining data using an array of parameters + 'body' => ['parameter1' => 'value1', '...'], + + // using a closure to generate the uploaded data + 'body' => function () { + // ... + }, + + // using a resource to get the data from it + 'body' => fopen('/path/to/file', 'r'), + ]); + +When uploading data with the ``POST`` method, if you don't define the +``Content-Type`` HTTP header explicitly, Symfony assumes that you're uploading +form data and adds the required +``'Content-Type: application/x-www-form-urlencoded'`` header for you. + +When uploading JSON payloads, use the ``json`` option instead of ``body``. The +given content will be JSON-encoded automatically and the request will add the +``Content-Type: application/json`` automatically too:: + + $response = $httpClient->request('POST', 'https://...', [ + 'json' => ['param1' => 'value1', '...'], + ]); + +Cookies +~~~~~~~ + +The HTTP client provided by this component is stateless but handling cookies +requires a stateful storage (because responses can update cookies and they must +be used for subsequent requests). That's why this component doesn't handle +cookies automatically. + +You can either handle cookies yourself using the ``Cookie`` HTTP header or use +the :doc:`BrowserKit component ` which provides this +feature and integrates seamlessly with the HttpClient component. + +Redirects +~~~~~~~~~ + +By default, the HTTP client follows redirects, up to a maximum of 20, when +making a request. Use the ``max_redirects`` setting to configure this behavior +(if the number of redirects is higher than the configured value, you'll get a +:class:`Symfony\\Component\\HttpClient\\Exception\\RedirectionException`):: + + $response = $httpClient->request('GET', 'https://...', [ + // 0 means to not follow any redirect + 'max_redirects' => 0, + ]); + +.. Concurrent Requests +.. ~~~~~~~~~~~~~~~~~~~ +.. +.. +.. TODO +.. +.. + +Processing Responses +-------------------- + +The response returned by all HTTP clients is an object of type +:class:`Symfony\\Contracts\\HttpClient\\ResponseInterface` which provides the +following methods:: + + $response = $httpClient->request('GET', 'https://...'); + + // gets the HTTP status code of the response + $statusCode = $response->getStatusCode(); + + // gets the HTTP headers as string[][] with the header names lower-cased + $headers = $response->getHeaders(); + + // gets the response body as a string + $content = $response->getContent(); + + // returns info coming from the transport layer, such as "response_headers", + // "redirect_count", "start_time", "redirect_url", etc. + $httpInfo = $response->getInfo(); + // you can get individual info too + $startTime = $response->getInfo('start_time'); + +.. _http-client-streaming-responses: + +Streaming Responses +~~~~~~~~~~~~~~~~~~~ + +Call to the ``stream()`` method of the HTTP client to get *chunks* of the +response sequentially instead of waiting for the entire response:: + + $url = 'https://releases.ubuntu.com/18.04.1/ubuntu-18.04.1-desktop-amd64.iso'; + $response = $httpClient->request('GET', $url, [ + // optional: if you don't want to buffer the response in memory + 'buffer' => false, + // optional: to display details about the response progress + 'on_progress' => function (int $dlNow, int $dlSize, array $info): void { + // ... + }, + ]); + + // Responses are lazy: this code is executed as soon as headers are received + if (200 !== $response->getStatusCode()) { + throw new \Exception('...'); + } + + // get the response contents in chunk and save them in a file + // response chunks implement Symfony\Contracts\HttpClient\ChunkInterface + $fileHandler = fopen('/ubuntu.iso', 'w'); + foreach ($httpClient->stream($response) as $chunk) { + fwrite($fileHandler, $chunk->getContent();); + } + +Handling Exceptions +~~~~~~~~~~~~~~~~~~~ + +When the HTTP status code of the response is not in the 200-299 range (i.e. 3xx, +4xx or 5xx) your code is expected to handle it. If you don't do that, the +``getHeaders()`` and ``getContent()`` methods throw an appropriate exception:: + + // the response of this request will be a 403 HTTP error + $response = $httpClient->request('GET', 'https://httpbin.org/status/403'); + + // this code results in a Symfony\Component\HttpClient\Exception\ClientException + // because it doesn't check the status code of the response + $content = $response->getContent(); + + // pass FALSE as the optional argument to not throw an exception and + // return instead an empty string + $content = $response->getContent(false); + +Caching Requests and Responses +------------------------------ + +This component provides a special HTTP client via the +:class:`Symfony\\Component\\HttpClient\\CachingHttpClient` class to cache +requests and their responses. The actual HTTP caching is implemented using the +:doc:`HttpKernel component `, so make sure it's +installed in your application. + +.. +.. TODO: +.. Show some example of caching requests+responses +.. +.. + +Scoping Client +-------------- + +It's common that some of the HTTP client options depend on the URL of the +request (e.g. you must set some headers when making requests to GitHub API but +not for other hosts). If that's your case, this component provides a special +HTTP client via the :class:`Symfony\\Component\\HttpClient\\ScopingHttpClient` +class to autoconfigure the HTTP client based on the requested URL:: + + use Symfony\Component\HttpClient\HttpClient; + use Symfony\Component\HttpClient\ScopingHttpClient; + + $client = HttpClient::create(); + $httpClient = new ScopingHttpClient($client, [ + // the key is a regexp which must match the beginning of the request URL + 'https://api\.github\.com/' => [ + 'headers' => [ + 'Accept' => 'application/vnd.github.v3+json', + 'Authorization' => 'token '.$githubToken, + ], + ], + + // use a '*' wildcard to apply some options to all requests + '*' => [ + // ... + ] + ]); + +If the request URL is relative (because you use the ``base_uri`` option), the +scoping HTTP client can't make a match. That's why you can define a third +optional argument in its constructor which will be considered the default +regular expression applied to relative URLs:: + + // ... + + $httpClient = new ScopingHttpClient($client, [ + 'https://api\.github\.com/' => [ + 'base_uri' => 'https://api.github.com/', + // ... + ], + + '*' => [ + // ... + ] + ], + // this is the regexp applied to all relative URLs + 'https://api\.github\.com/' + ); + +PSR-7 and PSR-18 Compatibility +------------------------------ + +This component uses its own interfaces and exception classes different from the +ones defined in `PSR-7`_ (HTTP message interfaces) and `PSR-18`_ (HTTP Client). +However, it includes the :class:`Symfony\\Component\\HttpClient\\Psr18Client` +class, which is an adapter to turn a Symfony ``HttpClientInterface`` into a +PSR-18 ``ClientInterface``. + +Before using it in your application, run the following commands to install the +required dependencies: + +.. code-block:: terminal + + # installs the base ClientInterface + $ composer require psr/http-client + + # installs an efficient implementation of response and stream factories + # with autowiring aliases provided by Symfony Flex + $ composer require nyholm/psr7 + +Now you can make HTTP requests with the PSR-18 client as follows:: + + use Nyholm\Psr7\Factory\Psr17Factory; + use Symfony\Component\HttpClient\Psr18Client; + + $psr17Factory = new Psr17Factory(); + $psr18Client = new Psr18Client(); + + $url = 'https://symfony.com/versions.json'; + $request = $psr17Factory->createRequest('GET', $url); + $response = $psr18Client->sendRequest($request); + + $content = json_decode($response->getBody()->getContents(), true); + +Symfony Framework Integration +----------------------------- + +When using this component in a full-stack Symfony application, you can configure +multiple clients with different configurations and inject them into your services. + +Configuration +~~~~~~~~~~~~~ + +Use the ``framework.http_client`` key to configure the default HTTP client used +in the application. Check out the full +:ref:`http_client config reference ` to learn about all +the available config options: + +.. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + http_client: + max_redirects: 7 + max_host_connections: 10 + +If you want to define multiple HTTP clients, use this other expanded configuration: + +.. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + http_client: + http_clients: + crawler: + headers: [{ 'X-Powered-By': 'ACME App' }] + http_version: '1.0' + default: + max_host_connections: 10 + max_redirects: 7 + +Injecting the HTTP Client Into Services +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If your application only defines one HTTP client, you can inject it into any +service by type-hinting a constructor argument with the +:class:`Symfony\\Contracts\\HttpClient\\HttpClientInterface`:: + + use Symfony\Contracts\HttpClient\HttpClientInterface; + + class SomeService + { + private $httpClient; + + public function __construct(HttpClientInterface $httpClient) + { + $this->httpClient = $httpClient; + } + } + +If you have several clients, you must use any of the methods defined by Symfony +to ref:`choose a specific service `. Each client +has a unique service named after its configuration. + +.. code-block:: yaml + + # config/services.yaml + services: + # ... + + # whenever a service type-hints HttpClientInterface, inject the GitHub client + Symfony\Contracts\HttpClient\HttpClientInterface: '@api_client.github' + + # inject the HTTP client called 'crawler' into this argument of this service + App\Some\Service: + $someArgument: '@http_client.crawler' + +Testing HTTP Clients and Responses +---------------------------------- + +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. + +The first way of using ``MockHttpClient`` is to configure the set of responses +to return using its constructor:: + + use Symfony\Component\HttpClient\MockHttpClient; + use Symfony\Component\HttpClient\Response\MockResponse; + + $responses = [ + new MockResponse($body1, $info1), + new MockResponse($body2, $info2), + ]; + + $client = new MockHttpClient($responses); + // responses are returned in the same order as passed to MockHttpClient + $response1 = $client->request('...'); // returns $responses[0] + $response2 = $client->request('...'); // returns $responses[1] + +Another way of using ``MockHttpClient`` is to pass a callback that generates the +responses dynamically when it's called:: + + use Symfony\Component\HttpClient\MockHttpClient; + use Symfony\Component\HttpClient\Response\MockResponse; + + $callback = function ($method, $url, $options) { + return new MockResponse('...'); + }; + + $client = new MockHttpClient($callback); + $response = $client->request('...'); // calls $callback to get the response + +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)``). + +However, using ``MockResponse`` allows simulating chunked responses and timeouts:: + + $body = function () { + yield 'hello'; + // empty strings are turned into timeouts so that they are easy to test + yield ''; + yield 'world'; + }; + + $mockResponse = new MockResponse($body()); + +.. _`cURL PHP extension`: https://php.net/curl +.. _`PSR-7`: https://www.php-fig.org/psr/psr-7/ +.. _`PSR-18`: https://www.php-fig.org/psr/psr-18/ diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 396df31d3d3..6c766f5f745 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -88,6 +88,33 @@ Configuration * `hinclude_default_template`_ * :ref:`path ` +* `http_client`_ + + * `auth_basic`_ + * `auth_bearer`_ + * `base_uri`_ + * `bindto`_ + * `buffer`_ + * `cafile`_ + * `capath`_ + * `capture_peer_cert_chain`_ + * `ciphers`_ + * `headers`_ + * `http_version`_ + * `local_cert`_ + * `local_pk`_ + * `max_host_connections`_ + * `max_redirects`_ + * `no_proxy`_ + * `passphrase`_ + * `peer_fingerprint`_ + * `proxy`_ + * `query`_ + * `resolve`_ + * `timeout`_ + * `verify_host`_ + * `verify_peer`_ + * `http_method_override`_ * `ide`_ * :ref:`lock ` @@ -626,6 +653,270 @@ path The path prefix for fragments. The fragment listener will only be executed when the request starts with this path. +.. _reference-http-client: + +http_client +~~~~~~~~~~~ + +If there's only one HTTP client defined in the app, you can configure it +directly under the ``framework.http_client`` option: + +.. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + http_client: + headers: [{ 'X-Powered-By': 'ACME App' }] + max_host_connections: 10 + max_redirects: 7 + +If the app defines multiple HTTP clients, you must give them a unique name and +define them under the type of HTTP client you are creating (``http_clients`` for +regular clients and ``api_clients`` for clients that include utilities to +consume APIs): + +.. code-block:: yaml + + # config/packages/framework.yaml + framework: + # ... + http_client: + http_clients: + crawler: + # ... + default: + # ... + api_clients: + github: + # ... + +auth_basic +.......... + +**type**: ``array`` + +The username and password used to create the ``Authorization`` HTTP header +used in HTTP Basic authentication. The value of this option must follow the +format ``['username', 'password']``. + +auth_bearer +........... + +**type**: ``string`` + +The token used to create the ``Authorization`` HTTP header used in HTTP Bearer +authentication (also called token authentication). + +base_uri +........ + +**type**: ``string`` + +URI that is merged into relative URIs, following the rules explained in the +`RFC 3986`_ standard. This is useful when all the requests you make share a +common prefix (e.g. ``https://api.github.com/``) so you can avoid adding it to +every request. + +Here are some common examples of how ``base_uri`` merging works in practice: + +=================== ============== ====================== +``base_uri`` Relative URI Actual Requested URI +=================== ============== ====================== +http://foo.com /bar http://foo.com/bar +http://foo.com/foo /bar http://foo.com/bar +http://foo.com/foo bar http://foo.com/bar +http://foo.com/foo/ bar http://foo.com/foo/bar +http://foo.com http://baz.com http://baz.com +http://foo.com/?bar bar http://foo.com/bar +=================== ============== ====================== + +bindto +...... + +**type**: ``string`` + +A network interface name, IP address, a host name or a UNIX socket to use as the +outgoing network interface. + +buffer +...... + +**type**: ``boolean`` + +.. TODO: improve this useless description + +Indicates if the response should be buffered or not. + +cafile +...... + +**type**: ``string`` + +The path of the certificate authority file that contains one or more +certificates used to verify the other servers' certificates. + +capath +...... + +**type**: ``string`` + +The path to a directory that contains one or more certificate authority files. + +capture_peer_cert_chain +....................... + +**type**: ``boolean`` + +If ``true``, the response includes a ``peer_certificate_chain`` attribute with +the peer certificates (OpenSSL X.509 resources). + +ciphers +....... + +**type**: ``string`` + +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'``). + +headers +....... + +**type**: ``array`` + +An associative array of the HTTP headers added before making the request. This +value must use the format ``['header-name' => header-value, ...]``. + +http_version +............ + +**type**: ``string`` | ``null`` **default**: ``null`` + +The HTTP version to use, typically ``'1.1'`` or ``'2.0'``. Leave it to ``null`` +to let Symfony select the best version automatically. + +local_cert +.......... + +**type**: ``string`` + +The path to a file that contains the `PEM formatted`_ certificate used by the +HTTP client. This is often combined with the ``local_pk`` and ``passphrase`` +options. + +local_pk +........ + +**type**: ``string`` + +The path of a file that contains the `PEM formatted`_ private key of the +certificate defined in the ``local_cert`` option. + +max_host_connections +.................... + +**type**: ``integer`` **default**: ``6`` + +Defines the maximum amount of simultaneously open connections to a single host +(considering a "host" the same as a "host name + port number" pair). This limit +also applies for proxy connections, where the proxy is considered to be the host +for which this limit is applied. + +max_redirects +............. + +**type**: ``integer`` **default**: ``20`` + +The maximum number of redirects to follow. Use ``0`` to not follow any +redirection. + +no_proxy +........ + +**type**: ``string`` | ``null`` **default**: ``null`` + +A comma separated list of hosts that do not require a proxy to be reached, even +if one is configured. Use the ``'*'`` wildcard to match all hosts and an empty +string to match none (disables the proxy). + +passphrase +.......... + +**type**: ``string`` + +The passphrase used to encrypt the certificate stored in the file defined in the +``local_cert`` option. + +peer_fingerprint +................ + +**type**: ``array`` + +When negotiating a TLS or SSL connection, the server sends a certificate +indicating its identity. A public key is extracted from this certificate and if +it does not exactly match any of the public keys provided in this option, the +connection is aborted before sending or receiving any data. + +The value of this option is an associative array of ``algorithm => hash`` +(e.g ``['pin-sha256' => '...']``). + +proxy +..... + +**type**: ``string`` | ``null`` + +The HTTP proxy to use to make the requests. Leave it to ``null`` to detect the +proxy automatically based on your system configuration. + +query +..... + +**type**: ``array`` + +An associative array of the query string values added to the URL before making +the request. This value must use the format ``['parameter-name' => parameter-value, ...]``. + +resolve +....... + +**type**: ``array`` + +A list of hostnames and their IP addresses to pre-populate the DNS cache used by +the HTTP client in order to avoid a DNS lookup for those hosts. This option is +useful both to improve performance 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', ...]``). + +timeout +....... + +**type**: ``float`` **default**: depends on your PHP config + +Time, in seconds, to wait for a response. If the response takes longer, a +:class:`Symfony\\Component\\HttpClient\\Exception\\TransportException` is thrown. +Its default value is the same as the value of PHP's `default_socket_timeout`_ +config option. + +verify_host +........... + +**type**: ``boolean`` + +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 +combined with ``verify_peer`` to also verify the certificate authenticity. + +verify_peer +........... + +**type**: ``boolean`` + +If ``true``, the certificate sent by other servers when negotiating a TLS or SSL +connection is verified for authenticity. Authenticating the certificate is not +enough to be sure about the server, so you should combine this with the +``verify_host`` option. + profiler ~~~~~~~~ @@ -2410,3 +2701,6 @@ to know their differences. .. _`session.sid_length PHP option`: https://php.net/manual/session.configuration.php#ini.session.sid-length .. _`session.sid_bits_per_character PHP option`: https://php.net/manual/session.configuration.php#ini.session.sid-bits-per-character .. _`X-Robots-Tag HTTP header`: https://developers.google.com/search/reference/robots_meta_tag +.. _`RFC 3986`: https://www.ietf.org/rfc/rfc3986.txt +.. _`default_socket_timeout`: https://php.net/manual/en/filesystem.configuration.php#ini.default-socket-timeout +.. _`PEM formatted`: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail From 1b98723374202fbd18f76ce78c85b3c1692065c2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 30 Apr 2019 16:39:53 +0200 Subject: [PATCH 133/499] Documented the intltimezone input type --- reference/forms/types/timezone.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst index a12602fa9a1..96e61de0d34 100644 --- a/reference/forms/types/timezone.rst +++ b/reference/forms/types/timezone.rst @@ -65,8 +65,13 @@ input The format of the *input* data - i.e. the format that the timezone is stored on your underlying object. Valid values are: +* ``datetimezone`` (a ``\DateTimeZone`` object) +* ``intltimezone`` (an ``\IntlTimeZone`` object) * ``string`` (e.g. ``America/New_York``) -* ``datetimezone`` (a ``DateTimeZone`` object) + +.. versionadded:: 4.3 + + The ``intltimezone`` input type was introduced in Symfony 4.3. regions ~~~~~~~ From 034fe48f488798b185b7b813c4fa517a336120d7 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 3 May 2019 12:31:25 +0200 Subject: [PATCH 134/499] fix indention --- components/mime.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mime.rst b/components/mime.rst index 085145f5abc..59a2ba3220f 100644 --- a/components/mime.rst +++ b/components/mime.rst @@ -625,7 +625,7 @@ You can register your own MIME type guesser by creating a class that implements public function isGuesserSupported(): bool { // return true when the guesser is supported (might depend on the OS for instance) - return true; + return true; } public function guessMimeType(string $path): ?string From 632d8e1d82b1b377fc467d90d790dda4164085a0 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 7 May 2019 12:25:32 +0200 Subject: [PATCH 135/499] [Mime] Use constants instead of numbers to set email priority --- components/mime.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mime.rst b/components/mime.rst index 59a2ba3220f..648fd13c7e2 100644 --- a/components/mime.rst +++ b/components/mime.rst @@ -50,7 +50,7 @@ methods to compose the entire email message:: ->cc('bar@example.com') ->bcc('baz@example.com') ->replyTo('fabien@symfony.com') - ->priority(1) + ->priority(Email::PRIORITY_HIGH) ->subject('Important Notification') ->text('Lorem ipsum...') ->html('

Lorem ipsum

...

') From 1444b136ffd46ab57c389c20dd7e2ec8e9361e6c Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 7 May 2019 13:56:35 +0200 Subject: [PATCH 136/499] fix build --- components/security/authentication.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 220500c26f0..7fd59c6c857 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -283,7 +283,7 @@ security.authentication.success ``AuthenticationEvents::AUTHENTICATION_SUCCESS` 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:`Symfony\Component\Security\Http\EventDeauthenticatedEvent` +security.logout_on_change ``Symfony\Component\Security\Http\Event\DeauthenticatedEvent`` :class:`Symfony\\Component\\Security\\Http\\EventDeauthenticatedEvent` =============================== ================================================================= ============================================================================== Authentication Success and Failure Events From 0ee3a0e0b866bcf6cb4fad5fc5e7bfe2aed015b1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 7 May 2019 14:48:21 +0200 Subject: [PATCH 137/499] Fixed the name of some methods --- components/mime.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/mime.rst b/components/mime.rst index 648fd13c7e2..333812df449 100644 --- a/components/mime.rst +++ b/components/mime.rst @@ -308,7 +308,7 @@ some utility methods for Twig templates:: $email = (new TemplatedEmail()) ->from('fabien@symfony.com') - ->fo('foo@example.com') + ->to('foo@example.com') // ... // this method defines the path of the Twig template to render @@ -373,7 +373,7 @@ the ``TemplatedEmail`` class:: $email = (new TemplatedEmail()) ->from('fabien@symfony.com') - ->fo('foo@example.com') + ->to('foo@example.com') // ... ->textTemplate('messages/user/signup.txt.twig') From 80e44ee873a49c8f60ba4a102e41e0004d17477a Mon Sep 17 00:00:00 2001 From: Andrey Bolonin Date: Mon, 6 May 2019 19:24:05 +0300 Subject: [PATCH 138/499] Update and rename from_flat_php_to_symfony2.rst to from_flat_php_to_symfony.rst --- ..._flat_php_to_symfony2.rst => from_flat_php_to_symfony.rst} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename introduction/{from_flat_php_to_symfony2.rst => from_flat_php_to_symfony.rst} (99%) diff --git a/introduction/from_flat_php_to_symfony2.rst b/introduction/from_flat_php_to_symfony.rst similarity index 99% rename from introduction/from_flat_php_to_symfony2.rst rename to introduction/from_flat_php_to_symfony.rst index 3af19f3fce1..27ec9190253 100644 --- a/introduction/from_flat_php_to_symfony2.rst +++ b/introduction/from_flat_php_to_symfony.rst @@ -1,7 +1,7 @@ .. index:: single: Symfony versus Flat PHP -.. _symfony2-versus-flat-php: +.. _symfony-versus-flat-php: Symfony versus Flat PHP ======================= @@ -523,7 +523,7 @@ allowing HTTP headers and content to be added via an object-oriented interface. And while the responses in this application are simple, this flexibility will pay dividends as your application grows. -.. _the-sample-application-in-symfony2: +.. _the-sample-application-in-symfony: The Sample Application in Symfony ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From d18a88f704fa9e771b6528bc5b3ba005ee95688c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 7 May 2019 14:53:25 +0200 Subject: [PATCH 139/499] Added a redirection for a renamed article --- _build/redirection_map | 1 + introduction/from_flat_php_to_symfony.rst | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/_build/redirection_map b/_build/redirection_map index b36960f5e9e..7e8c54bd737 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -416,3 +416,4 @@ /contributing/code/patches /contributing/code/pull_requests /workflow/state-machines /workflow/introduction /workflow/usage /workflow +/introduction/from_flat_php_to_symfony2 /introduction/from_flat_php_to_symfony diff --git a/introduction/from_flat_php_to_symfony.rst b/introduction/from_flat_php_to_symfony.rst index 27ec9190253..3af19f3fce1 100644 --- a/introduction/from_flat_php_to_symfony.rst +++ b/introduction/from_flat_php_to_symfony.rst @@ -1,7 +1,7 @@ .. index:: single: Symfony versus Flat PHP -.. _symfony-versus-flat-php: +.. _symfony2-versus-flat-php: Symfony versus Flat PHP ======================= @@ -523,7 +523,7 @@ allowing HTTP headers and content to be added via an object-oriented interface. And while the responses in this application are simple, this flexibility will pay dividends as your application grows. -.. _the-sample-application-in-symfony: +.. _the-sample-application-in-symfony2: The Sample Application in Symfony ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From f5b081e4046bf2a619dece1056693e1c1dd2b5d7 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 6 May 2019 15:32:13 +0200 Subject: [PATCH 140/499] Updated the configuration reference for NotCompromisedPassword constraint --- reference/configuration/framework.rst | 61 +++++++++++++------ .../constraints/NotCompromisedPassword.rst | 2 +- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index ef08f9e27d9..d0e76c61b00 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -211,7 +211,6 @@ Configuration * `validation`_ * :ref:`cache ` - * :ref:`disable_not_compromised_password ` * `email_validation_mode`_ * :ref:`enable_annotations ` * :ref:`enabled ` @@ -219,6 +218,11 @@ Configuration * :ref:`paths ` + * :ref:`not_compromised_password ` + + * :ref:`enabled ` + * `endpoint`_ + * `static_method`_ * `strict_email`_ * `translation_domain`_ @@ -2084,42 +2088,62 @@ has to implement the :class:`Symfony\\Component\\Validator\\Mapping\\Cache\\Cach Set this option to ``validator.mapping.cache.doctrine.apc`` to use the APC cache provide from the Doctrine project. -.. _reference-validation-disable_not_compromised_password: +.. _reference-validation-enable_annotations: -disable_not_compromised_password -................................ +enable_annotations +.................. **type**: ``boolean`` **default**: ``false`` -.. versionadded:: 4.3 +If this option is enabled, validation constraints can be defined using annotations. - The ``disable_not_compromised_password`` option was introduced in Symfony 4.3. +translation_domain +.................. + +**type**: ``string`` **default**: ``validators`` + +The translation domain that is used when translating validation constraint +error messages. + +.. _reference-validation-not-compromised-password: + +not_compromised_password +~~~~~~~~~~~~~~~~~~~~~~~~ The :doc:`NotCompromisedPassword ` constraint makes HTTP requests to a public API to check if the given password has been compromised in a data breach. +.. _reference-validation-not-compromised-password-enabled: + +enabled +....... + +**type**: ``boolean`` **default**: ``false`` + +.. versionadded:: 4.3 + + The ``enabled`` option was introduced in Symfony 4.3. + If you set this option to ``true``, no HTTP requests will be made and the given password will be considered valid. This is useful when you don't want or can't make HTTP requests, such as in ``dev`` and ``test`` environments or in continuous integration servers. -.. _reference-validation-enable_annotations: - -enable_annotations -.................. - -**type**: ``boolean`` **default**: ``false`` +endpoint +........ -If this option is enabled, validation constraints can be defined using annotations. +**type**: ``string`` **default**: ``null`` -translation_domain -.................. +.. versionadded:: 4.3 -**type**: ``string`` **default**: ``validators`` + The ``endpoint`` option was introduced in Symfony 4.3. -The translation domain that is used when translating validation constraint -error messages. +By default, the :doc:`NotCompromisedPassword ` +constraint uses the public API provided by `haveibeenpwned.com`_. This option +allows to define a different, but compatible, API endpoint to make the password +checks. It's useful for example when the Symfony application is run in an +intranet without public access to Internet. static_method ............. @@ -2717,3 +2741,4 @@ to know their differences. .. _`RFC 3986`: https://www.ietf.org/rfc/rfc3986.txt .. _`default_socket_timeout`: https://php.net/manual/en/filesystem.configuration.php#ini.default-socket-timeout .. _`PEM formatted`: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail +.. _`haveibeenpwned.com`: https://haveibeenpwned.com/ diff --git a/reference/constraints/NotCompromisedPassword.rst b/reference/constraints/NotCompromisedPassword.rst index 641596cc648..10aeded0e06 100644 --- a/reference/constraints/NotCompromisedPassword.rst +++ b/reference/constraints/NotCompromisedPassword.rst @@ -100,7 +100,7 @@ For example, if the password is ``test``, the entire SHA-1 hash is .. seealso:: When using this constraint inside a Symfony application, define the - :ref:`disable_not_compromised_password ` + :ref:`not_compromised_password ` option to avoid making HTTP requests in the ``dev`` and ``test`` environments. Available Options From 9590a37fa8493fb1ae014fe6df3e85ab5ae6c11f Mon Sep 17 00:00:00 2001 From: Thomas Schulz Date: Wed, 8 May 2019 09:13:44 +0200 Subject: [PATCH 141/499] Fix small typo in mime doc example --- components/mime.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/mime.rst b/components/mime.rst index 333812df449..8c822772b2a 100644 --- a/components/mime.rst +++ b/components/mime.rst @@ -398,7 +398,7 @@ simplify things later:: // ... $templateLoader = new FilesystemLoader(__DIR__.'/templates'); - $templatedLoader->addPath(__DIR__.'/images', 'images'); + $templateLoader->addPath(__DIR__.'/images', 'images'); $twig = new Environment($templateLoader); Now, use the special ``email.image()`` Twig helper to embed the images inside From cccf79c56ef24f072f85d2dc0c2e63ba4e18d367 Mon Sep 17 00:00:00 2001 From: Andrii Dembitskyi Date: Wed, 8 May 2019 15:12:37 +0300 Subject: [PATCH 142/499] Fix php config example for hinclude_default_template --- templating/hinclude.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/templating/hinclude.rst b/templating/hinclude.rst index 396dec13643..ee5047cc124 100644 --- a/templating/hinclude.rst +++ b/templating/hinclude.rst @@ -93,9 +93,7 @@ in your application configuration: $container->loadFromExtension('framework', [ // ... 'fragments' => [ - 'hinclude_default_template' => [ - 'hinclude.html.twig', - ], + 'hinclude_default_template' => 'hinclude.html.twig', ], ]); From a9788bcf7016b0908b3a27a0d26dfd590880ea78 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 9 May 2019 09:36:53 +0200 Subject: [PATCH 143/499] [Intl] Renamed Regions to Countries --- components/intl.rst | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/components/intl.rst b/components/intl.rst index 43b7c77425a..1acef5e809d 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -212,7 +212,7 @@ Accessing ICU Data This component provides the following ICU data: * `Language and Script Names`_ -* `Country and Region Names`_ +* `Country Names`_ * `Locales`_ * `Currencies`_ * `Timezones`_ @@ -283,42 +283,40 @@ You can also check if a given script code is valid:: The ``Scripts`` class was introduced in Symfony 4.3. -.. _country-names: +Country Names +~~~~~~~~~~~~~ -Country and Region Names -~~~~~~~~~~~~~~~~~~~~~~~~ +The ``Countries`` class provides access to the name of all countries according +to the `ISO 3166-1 alpha-2`_ list of officially recognized countries and +territories:: -In the world there are some territorial disputes that make it hard to define -what a country is. That's why the Intl component provides a ``Regions`` class -instead of a ``Countries`` class:: - - use Symfony\Component\Intl\Regions; + use Symfony\Component\Intl\Countries; \Locale::setDefault('en'); - $countries = Regions::getNames(); - // ('regionCode' => 'regionName') + $countries = Countries::getNames(); + // ('countryCode' => 'countryName') // => ['AF' => 'Afghanistan', 'AX' => 'Åland Islands', ...] - $country = Regions::getName('GB'); + $country = Countries::getName('GB'); // => 'United Kingdom' All methods accept the translation locale as the last, optional parameter, which defaults to the current default locale:: - $countries = Regions::getNames('de'); + $countries = Countries::getNames('de'); // => ['AF' => 'Afghanistan', 'EG' => 'Ägypten', ...] - $country = Regions::getName('GB', 'de'); + $country = Countries::getName('GB', 'de'); // => 'Vereinigtes Königreich' -You can also check if a given region code is valid:: +You can also check if a given country code is valid:: - $isValidRegion = Regions::exists($regionCode); + $isValidCountry = Countries::exists($countryCode); .. versionadded:: 4.3 - The ``Regions`` class was introduced in Symfony 4.3. + The ``Countries`` class was introduced in Symfony 4.3. Locales ~~~~~~~ @@ -451,3 +449,4 @@ Learn more .. _install the intl extension: https://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 +.. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 From e861d6434db149f8438ba86037db17d8823f8af7 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 9 May 2019 19:37:23 +0200 Subject: [PATCH 144/499] use ordered use statements for php code examples --- components/http_client.rst | 2 +- reference/constraints/Json.rst | 2 +- reference/constraints/Negative.rst | 2 +- reference/constraints/NegativeOrZero.rst | 2 +- reference/constraints/NotCompromisedPassword.rst | 4 +--- reference/constraints/Positive.rst | 3 ++- reference/constraints/PositiveOrZero.rst | 2 +- reference/constraints/Timezone.rst | 2 +- reference/constraints/Unique.rst | 2 +- 9 files changed, 10 insertions(+), 11 deletions(-) diff --git a/components/http_client.rst b/components/http_client.rst index 2a99653a1ed..40f6c182693 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -52,8 +52,8 @@ including concurrent requests, HTTP/2 is only supported when using cURL. is enabled and falls back to PHP streams otherwise. If you prefer to select the transport explicitly, use the following classes to create the client:: - use Symfony\Component\HttpClient\NativeHttpClient; use Symfony\Component\HttpClient\CurlHttpClient; + use Symfony\Component\HttpClient\NativeHttpClient; // uses native PHP streams $httpClient = new NativeHttpClient(); diff --git a/reference/constraints/Json.rst b/reference/constraints/Json.rst index 4590b847c57..beac690c4f9 100644 --- a/reference/constraints/Json.rst +++ b/reference/constraints/Json.rst @@ -69,8 +69,8 @@ The ``Json`` constraint can be applied to a property or a "getter" method: // src/Entity/Book.php namespace App\Entity; - use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; class Book { diff --git a/reference/constraints/Negative.rst b/reference/constraints/Negative.rst index 0a0d53002a3..c90a1fb1c98 100644 --- a/reference/constraints/Negative.rst +++ b/reference/constraints/Negative.rst @@ -69,8 +69,8 @@ The following constraint ensures that the ``withdraw`` of a bank account // src/Entity/TransferItem.php namespace App\Entity; - use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; class TransferItem { diff --git a/reference/constraints/NegativeOrZero.rst b/reference/constraints/NegativeOrZero.rst index 6b92c8900d2..15d0926bc5d 100644 --- a/reference/constraints/NegativeOrZero.rst +++ b/reference/constraints/NegativeOrZero.rst @@ -68,8 +68,8 @@ is a negative number or equal to zero: // src/Entity/UnderGroundGarage.php namespace App\Entity; - use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; class UnderGroundGarage { diff --git a/reference/constraints/NotCompromisedPassword.rst b/reference/constraints/NotCompromisedPassword.rst index 10aeded0e06..ffa9fe99d8d 100644 --- a/reference/constraints/NotCompromisedPassword.rst +++ b/reference/constraints/NotCompromisedPassword.rst @@ -36,8 +36,6 @@ The following constraint ensures that the ``rawPassword`` property of the class User { - // ... - /** * @Assert\NotCompromisedPassword */ @@ -72,8 +70,8 @@ The following constraint ensures that the ``rawPassword`` property of the // src/Entity/User.php namespace App\Entity; - use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; class User { diff --git a/reference/constraints/Positive.rst b/reference/constraints/Positive.rst index 28633551f60..b9bef408fa5 100644 --- a/reference/constraints/Positive.rst +++ b/reference/constraints/Positive.rst @@ -69,8 +69,9 @@ positive number (greater than zero): // src/Entity/Employee.php namespace App\Entity; - use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; + class Employee { diff --git a/reference/constraints/PositiveOrZero.rst b/reference/constraints/PositiveOrZero.rst index 7d668598e96..70196a6b9fa 100644 --- a/reference/constraints/PositiveOrZero.rst +++ b/reference/constraints/PositiveOrZero.rst @@ -68,8 +68,8 @@ is positive or zero: // src/Entity/Person.php namespace App\Entity; - use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; class Person { diff --git a/reference/constraints/Timezone.rst b/reference/constraints/Timezone.rst index 2fc04bdc839..c195a5d46f6 100644 --- a/reference/constraints/Timezone.rst +++ b/reference/constraints/Timezone.rst @@ -69,8 +69,8 @@ string meant to contain a timezone identifier (e.g. ``America/New_York``): // src/Entity/UserSettings.php namespace App\Entity; - use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; class UserSettings { diff --git a/reference/constraints/Unique.rst b/reference/constraints/Unique.rst index 681c4dc18b6..97cb6ff8602 100644 --- a/reference/constraints/Unique.rst +++ b/reference/constraints/Unique.rst @@ -78,8 +78,8 @@ strings: // src/Entity/Person.php namespace App\Entity; - use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Constraints as Assert; + use Symfony\Component\Validator\Mapping\ClassMetadata; class Person { From c22fade183080d61d3522dcb76de7f9e64541389 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sun, 7 Apr 2019 13:18:23 +0200 Subject: [PATCH 145/499] Add documentation for the Redis transport --- messenger.rst | 85 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/messenger.rst b/messenger.rst index bb52bba84ea..dddd282e886 100644 --- a/messenger.rst +++ b/messenger.rst @@ -135,8 +135,12 @@ Transports By default, messages are processed as soon as they are dispatched. If you prefer to process messages asynchronously, you must configure a transport. These transports communicate with your application via queuing systems or third parties. -The built-in AMQP transport allows you to communicate with most of the AMQP -brokers such as RabbitMQ. + +There are the following built-in transports: + + - AMQP + - Doctrine + - Redis .. note:: @@ -155,7 +159,7 @@ the messenger component, the following configuration should have been created: framework: messenger: transports: - amqp: "%env(MESSENGER_TRANSPORT_DSN)%" + your_transport: "%env(MESSENGER_TRANSPORT_DSN)%" .. code-block:: xml @@ -171,7 +175,7 @@ the messenger component, the following configuration should have been created: - +
@@ -182,33 +186,63 @@ the messenger component, the following configuration should have been created: $container->loadFromExtension('framework', [ 'messenger' => [ 'transports' => [ - 'amqp' => '%env(MESSENGER_TRANSPORT_DSN)%', + 'your_transport' => '%env(MESSENGER_TRANSPORT_DSN)%', ], ], ]); +This will also configure the following services for you: + +#. A ``messenger.sender.your_transport`` sender to be used when routing messages; +#. A ``messenger.receiver.your_transport`` receiver to be used when consuming messages. + +Now define the ``MESSENGER_TRANSPORT_DSN`` in the ``.env`` file. +See examples beneath how to configure the DSN for different transports. + +Amqp +~~~~ + .. code-block:: bash # .env - ###> symfony/messenger ### MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages - ###< symfony/messenger ### This is enough to allow you to route your message to the ``amqp`` transport. -This will also configure the following services for you: - -#. A ``messenger.sender.amqp`` sender to be used when routing messages; -#. A ``messenger.receiver.amqp`` receiver to be used when consuming messages. .. note:: In order to use Symfony's built-in AMQP transport, you will need the AMQP - PHP extension and the Serializer Component. Ensure that they are installed with: + PHP extension and the Serializer component. Ensure that they are installed with: .. code-block:: terminal $ composer require symfony/amqp-pack +Redis +~~~~~ + +The Redis transport will use `streams`_ to queue messages. + +.. code-block:: bash + + # .env + MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages + +This is enough to allow you to route your message to the Redis transport. + +If you have multiple systems to receive the same messages you could use different groups +to achieve this: + +.. code-block:: bash + + # .env + MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages/group1/consumer1 + +.. note:: + + In order to use Symfony's built-in Redis transport, you will need the Redis + PHP extension (^4.2), a running Redis server (^5.0) and the Serializer component. + Routing ------- @@ -225,7 +259,7 @@ configuration: framework: messenger: routing: - 'My\Message\Message': amqp # The name of the defined transport + 'My\Message\Message': your_transport # The name of the defined transport .. code-block:: xml @@ -242,7 +276,7 @@ configuration: - + @@ -254,7 +288,7 @@ configuration: $container->loadFromExtension('framework', [ 'messenger' => [ 'routing' => [ - 'My\Message\Message' => 'amqp', + 'My\Message\Message' => 'your_transport', ], ], ]); @@ -274,7 +308,7 @@ instead of a class name: messenger: routing: 'My\Message\MessageAboutDoingOperationalWork': another_transport - '*': amqp + '*': your_transport .. code-block:: xml @@ -294,7 +328,7 @@ instead of a class name: - + @@ -307,7 +341,7 @@ instead of a class name: 'messenger' => [ 'routing' => [ 'My\Message\Message' => 'another_transport', - '*' => 'amqp', + '*' => 'your_transport', ], ], ]); @@ -322,7 +356,7 @@ A class of messages can also be routed to multiple senders by specifying a list: framework: messenger: routing: - 'My\Message\ToBeSentToTwoSenders': [amqp, audit] + 'My\Message\ToBeSentToTwoSenders': [your_transport, audit] .. code-block:: xml @@ -339,7 +373,7 @@ A class of messages can also be routed to multiple senders by specifying a list: - + @@ -352,7 +386,7 @@ A class of messages can also be routed to multiple senders by specifying a list: $container->loadFromExtension('framework', [ 'messenger' => [ 'routing' => [ - 'My\Message\ToBeSentToTwoSenders' => ['amqp', 'audit'], + 'My\Message\ToBeSentToTwoSenders' => ['your_transport', 'audit'], ], ], ]); @@ -369,7 +403,7 @@ while still having them passed to their respective handler: messenger: routing: 'My\Message\ThatIsGoingToBeSentAndHandledLocally': - senders: [amqp] + senders: [your_transport] send_and_handle: true .. code-block:: xml @@ -387,7 +421,7 @@ while still having them passed to their respective handler: - + @@ -400,7 +434,7 @@ while still having them passed to their respective handler: 'messenger' => [ 'routing' => [ 'My\Message\ThatIsGoingToBeSentAndHandledLocally' => [ - 'senders' => ['amqp'], + 'senders' => ['your_transport'], 'send_and_handle' => true, ], ], @@ -415,7 +449,7 @@ most of the cases. To do so, use the ``messenger:consume`` command like this: .. code-block:: terminal - $ php bin/console messenger:consume amqp + $ php bin/console messenger:consume your_transport The first argument is the receiver's service name. It might have been created by your ``transports`` configuration or it can be your own receiver. @@ -835,3 +869,4 @@ Learn more /messenger/* .. _`enqueue's transport`: https://github.com/php-enqueue/messenger-adapter +.. _`streams`: https://redis.io/topics/streams-intro From daaf7b2d6656b0ca8071472650a4aad31e51372a Mon Sep 17 00:00:00 2001 From: Wouter J Date: Sat, 11 May 2019 21:22:52 +0200 Subject: [PATCH 146/499] [#11341] Added versionadded directive --- messenger.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/messenger.rst b/messenger.rst index dddd282e886..fb1ecec950c 100644 --- a/messenger.rst +++ b/messenger.rst @@ -138,9 +138,9 @@ transports communicate with your application via queuing systems or third partie There are the following built-in transports: - - AMQP - - Doctrine - - Redis +- `AMQP`_ +- Doctrine +- `Redis`_ .. note:: @@ -199,7 +199,7 @@ This will also configure the following services for you: Now define the ``MESSENGER_TRANSPORT_DSN`` in the ``.env`` file. See examples beneath how to configure the DSN for different transports. -Amqp +AMQP ~~~~ .. code-block:: bash @@ -221,6 +221,10 @@ This is enough to allow you to route your message to the ``amqp`` transport. Redis ~~~~~ +.. versionadded:: 4.3 + + The Redis transport was introduced in Symfony 4.3. + The Redis transport will use `streams`_ to queue messages. .. code-block:: bash From 2b902939d068b5322ccb5a4979e7d1611838f181 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 15 May 2019 14:38:38 +0200 Subject: [PATCH 147/499] Fix the doc about exception handling in the HttpClient component --- components/http_client.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/http_client.rst b/components/http_client.rst index 40f6c182693..e94e9119023 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -304,7 +304,7 @@ When the HTTP status code of the response is not in the 200-299 range (i.e. 3xx, $content = $response->getContent(); // pass FALSE as the optional argument to not throw an exception and - // return instead an empty string + // return instead the response content even for errors $content = $response->getContent(false); Caching Requests and Responses From 8fc8457589a2370bb8be0c17a66d6079c4a09528 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 15 May 2019 15:10:02 +0200 Subject: [PATCH 148/499] Minor reword --- components/http_client.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/http_client.rst b/components/http_client.rst index e94e9119023..96eee00c476 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -303,8 +303,8 @@ When the HTTP status code of the response is not in the 200-299 range (i.e. 3xx, // because it doesn't check the status code of the response $content = $response->getContent(); - // pass FALSE as the optional argument to not throw an exception and - // return instead the response content even for errors + // 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); Caching Requests and Responses From 730689c2e678a50fa3eca59848600c4d50f680a5 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 17 May 2019 16:23:43 +0200 Subject: [PATCH 149/499] Mentioned the deprecation of the threads config option --- reference/configuration/security.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index d25e415d83a..5fba7fc34ad 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -240,6 +240,12 @@ 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 From fb24e7b57f3327ed8896252ddcc41f00f61a913a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 19 May 2019 10:46:15 -0300 Subject: [PATCH 150/499] Improve doc for HttpClient --- components/http_client.rst | 80 +++++++-------- reference/configuration/framework.rst | 138 +++++++++++++++----------- 2 files changed, 119 insertions(+), 99 deletions(-) diff --git a/components/http_client.rst b/components/http_client.rst index 96eee00c476..0cb9cb3c9b9 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -6,12 +6,18 @@ 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. + PHP stream wrappers and cURL. It provides utilities to consume APIs and + supports synchronous and asynchronous operations. .. versionadded:: 4.3 The HttpClient component was introduced in Symfony 4.3. +.. TODO +.. tell about implementation vs abstraction +.. tell there are more options +.. tell chunked + compression are supported out of the box + Installation ------------ @@ -69,14 +75,15 @@ Enabling HTTP/2 Support ----------------------- HTTP/2 is only supported when using the cURL-based transport and the libcurl -version is >= 7.36.0. If you meet these requirements, you can enable HTTP/2 -explicitly via the ``http_version`` option:: +version is >= 7.36.0. If you meet these requirements, HTTP/2 will be used by +default when the request protocol is ``https``. If you need it for ``http``, +you must enable it explicitly via the ``http_version`` option:: $httpClient = HttpClient::create(['http_version' => '2.0']); -If you don't set the HTTP version explicitly, Symfony will use ``'2.0'`` only -when the request protocol is ``https://`` (and the cURL requirements mentioned -earlier are met). +Support for HTTP/2 PUSH works out of the box when libcurl >= 7.61.0 is used with +PHP >= 7.2.17 / 7.3.4: pushed responses are put into a temporary cache and are +used when a subsequent request is triggered for the corresponding URLs. Making Requests --------------- @@ -89,14 +96,13 @@ method to perform all kinds of HTTP requests:: $response = $httpClient->request('PUT', 'https://...'); // ... -Responses are always asynchronous, so they are ready as soon as the response -HTTP headers are received, instead of waiting to receive the entire response -contents:: +Responses are always asynchronous, so that the call to the method returns +immediately instead of waiting to receive the response:: + // code execution continues immediately; it doesn't wait to receive the response $response = $httpClient->request('GET', 'http://releases.ubuntu.com/18.04.2/ubuntu-18.04.2-desktop-amd64.iso'); - // code execution continues immediately; it doesn't wait to receive the response - // you can get the value of any HTTP response header + // getting the response headers waits until they arrive $contentType = $response->getHeaders()['content-type'][0]; // trying to get the response contents will block the execution until @@ -135,8 +141,8 @@ each request (which overrides any global authentication):: Query String Parameters ~~~~~~~~~~~~~~~~~~~~~~~ -You can either append them manually to the requested URL, or better, add them -as an associative array to the ``query`` option:: +You can either append them manually to the requested URL, or define them as an +associative array via the ``query`` option, that will be merged with the URL:: // it makes an HTTP GET request to https://httpbin.org/get?token=...&name=... $response = $httpClient->request('GET', 'https://httpbin.org/get', [ @@ -155,7 +161,7 @@ requests and the specific headers for each request:: // this header is added to all requests made by this client $httpClient = HttpClient::create(['headers' => [ - 'Accept-Encoding' => 'gzip', + 'User-Agent' => 'My Fancy App', ]]); // this header is only included in this request and overrides the value @@ -170,7 +176,7 @@ Uploading Data ~~~~~~~~~~~~~~ This component provides several methods for uploading data using the ``body`` -option. You can use regular strings, closures and resources and they'll be +option. You can use regular strings, closures, iterables and resources and they'll be processed automatically when making the requests:: $response = $httpClient->request('POST', 'https://...', [ @@ -264,7 +270,7 @@ following methods:: Streaming Responses ~~~~~~~~~~~~~~~~~~~ -Call to the ``stream()`` method of the HTTP client to get *chunks* of the +Call the ``stream()`` method of the HTTP client to get *chunks* of the response sequentially instead of waiting for the entire response:: $url = 'https://releases.ubuntu.com/18.04.1/ubuntu-18.04.1-desktop-amd64.iso'; @@ -286,13 +292,13 @@ response sequentially instead of waiting for the entire response:: // response chunks implement Symfony\Contracts\HttpClient\ChunkInterface $fileHandler = fopen('/ubuntu.iso', 'w'); foreach ($httpClient->stream($response) as $chunk) { - fwrite($fileHandler, $chunk->getContent();); + fwrite($fileHandler, $chunk->getContent()); } Handling Exceptions ~~~~~~~~~~~~~~~~~~~ -When the HTTP status code of the response is not in the 200-299 range (i.e. 3xx, +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()`` and ``getContent()`` methods throw an appropriate exception:: @@ -335,19 +341,15 @@ class to autoconfigure the HTTP client based on the requested URL:: use Symfony\Component\HttpClient\ScopingHttpClient; $client = HttpClient::create(); - $httpClient = new ScopingHttpClient($client, [ - // the key is a regexp which must match the beginning of the request URL + $client = new ScopingHttpClient($client, [ + // the options defined as values apply only to the URLs matching + // the regular expressions defined as keys 'https://api\.github\.com/' => [ 'headers' => [ 'Accept' => 'application/vnd.github.v3+json', 'Authorization' => 'token '.$githubToken, ], ], - - // use a '*' wildcard to apply some options to all requests - '*' => [ - // ... - ] ]); If the request URL is relative (because you use the ``base_uri`` option), the @@ -362,30 +364,25 @@ regular expression applied to relative URLs:: 'base_uri' => 'https://api.github.com/', // ... ], - - '*' => [ - // ... - ] ], // this is the regexp applied to all relative URLs 'https://api\.github\.com/' ); -PSR-7 and PSR-18 Compatibility ------------------------------- +PSR-18 Compatibility +-------------------- -This component uses its own interfaces and exception classes different from the -ones defined in `PSR-7`_ (HTTP message interfaces) and `PSR-18`_ (HTTP Client). -However, it includes the :class:`Symfony\\Component\\HttpClient\\Psr18Client` +This component uses and implements abstractions defined by the +``symfony/contracts`` package. It also implements the `PSR-18`_ (HTTP Client) +specifications via the :class:`Symfony\\Component\\HttpClient\\Psr18Client` class, which is an adapter to turn a Symfony ``HttpClientInterface`` into a PSR-18 ``ClientInterface``. -Before using it in your application, run the following commands to install the -required dependencies: +To use it, you need the ``psr/http-client`` package and a `PSR-17`_ implementation: .. code-block:: terminal - # installs the base ClientInterface + # installs the PSR-18 ClientInterface $ composer require psr/http-client # installs an efficient implementation of response and stream factories @@ -437,12 +434,11 @@ If you want to define multiple HTTP clients, use this other expanded configurati framework: # ... http_client: - http_clients: - crawler: + scoped_clients: + crawler.client: headers: [{ 'X-Powered-By': 'ACME App' }] http_version: '1.0' - default: - max_host_connections: 10 + some_api.client: max_redirects: 7 Injecting the HTTP Client Into Services @@ -533,5 +529,5 @@ However, using ``MockResponse`` allows simulating chunked responses and timeouts $mockResponse = new MockResponse($body()); .. _`cURL PHP extension`: https://php.net/curl -.. _`PSR-7`: https://www.php-fig.org/psr/psr-7/ +.. _`PSR-17`: https://www.php-fig.org/psr/psr-17/ .. _`PSR-18`: https://www.php-fig.org/psr/psr-18/ diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index d0e76c61b00..d8034ffc6aa 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -90,30 +90,51 @@ Configuration * `http_client`_ - * `auth_basic`_ - * `auth_bearer`_ - * `base_uri`_ - * `bindto`_ - * `buffer`_ - * `cafile`_ - * `capath`_ - * `capture_peer_cert_chain`_ - * `ciphers`_ - * `headers`_ - * `http_version`_ - * `local_cert`_ - * `local_pk`_ + * `default_options`_ + + * `bindto`_ + * `cafile`_ + * `capath`_ + * `ciphers`_ + * `headers`_ + * `http_version`_ + * `local_cert`_ + * `local_pk`_ + * `max_redirects`_ + * `no_proxy`_ + * `passphrase`_ + * `peer_fingerprint`_ + * `proxy`_ + * `resolve`_ + * `timeout`_ + * `verify_host`_ + * `verify_peer`_ + * `max_host_connections`_ - * `max_redirects`_ - * `no_proxy`_ - * `passphrase`_ - * `peer_fingerprint`_ - * `proxy`_ - * `query`_ - * `resolve`_ - * `timeout`_ - * `verify_host`_ - * `verify_peer`_ + * `scoped_clients`_ + + * `scope`_ + * `auth_basic`_ + * `auth_bearer`_ + * `base_uri`_ + * `bindto`_ + * `cafile`_ + * `capath`_ + * `ciphers`_ + * `headers`_ + * `http_version`_ + * `local_cert`_ + * `local_pk`_ + * `max_redirects`_ + * `no_proxy`_ + * `passphrase`_ + * `peer_fingerprint`_ + * `proxy`_ + * `query`_ + * `resolve`_ + * `timeout`_ + * `verify_host`_ + * `verify_peer`_ * `http_method_override`_ * `ide`_ @@ -662,8 +683,11 @@ when the request starts with this path. http_client ~~~~~~~~~~~ -If there's only one HTTP client defined in the app, you can configure it -directly under the ``framework.http_client`` option: +When the HttpClient component is installed, an HTTP client is available +as a service named ``http_client`` or using the autowiring alias +:class:`Symfony\\Constracts\\HttpClient\\HttpClientInterface`. + +This service can be configured using ``framework.http_client.default_options``: .. code-block:: yaml @@ -671,14 +695,15 @@ directly under the ``framework.http_client`` option: framework: # ... http_client: - headers: [{ 'X-Powered-By': 'ACME App' }] max_host_connections: 10 - max_redirects: 7 + default_options: + headers: [{ 'X-Powered-By': 'ACME App' }] + max_redirects: 7 -If the app defines multiple HTTP clients, you must give them a unique name and -define them under the type of HTTP client you are creating (``http_clients`` for -regular clients and ``api_clients`` for clients that include utilities to -consume APIs): +Multiple pre-configured HTTP client services can be defined, each with its +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 @@ -686,15 +711,21 @@ consume APIs): framework: # ... http_client: - http_clients: - crawler: - # ... - default: - # ... - api_clients: - github: + scoped_clients: + my_api.client: + 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 +use default options. + +Each scoped client also define a corresponding named autowiring alias. +E.g. if you use +``Symfony\Constracts\HttpClient\HttpClientInterface $myApiClient`` +as the type and name of an argument, autowiring will inject the ``my_api.client`` +service into your autowired classes. + auth_basic .......... @@ -743,15 +774,6 @@ bindto A network interface name, IP address, a host name or a UNIX socket to use as the outgoing network interface. -buffer -...... - -**type**: ``boolean`` - -.. TODO: improve this useless description - -Indicates if the response should be buffered or not. - cafile ...... @@ -767,14 +789,6 @@ capath The path to a directory that contains one or more certificate authority files. -capture_peer_cert_chain -....................... - -**type**: ``boolean`` - -If ``true``, the response includes a ``peer_certificate_chain`` attribute with -the peer certificates (OpenSSL X.509 resources). - ciphers ....... @@ -887,17 +901,27 @@ resolve A list of hostnames and their IP addresses to pre-populate the DNS cache used by the HTTP client in order to avoid a DNS lookup for those hosts. This option is -useful both to improve performance and to make your tests easier. +useful to improve security when IPs are checked before the URL is passed to the +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', ...]``). +scope +..... + +**type**: ``string`` + +For scoped clients only: the regular expression that the URL must match before +applying all other non-default options. By default, the scope is derived from +`base_uri`_. + timeout ....... **type**: ``float`` **default**: depends on your PHP config -Time, in seconds, to wait for a response. If the response takes longer, a +Time, in seconds, to wait for a response. If the response stales for longer, a :class:`Symfony\\Component\\HttpClient\\Exception\\TransportException` is thrown. Its default value is the same as the value of PHP's `default_socket_timeout`_ config option. From afdddbf536417233360bd194d2730d9e5329b88a Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Wed, 4 Jul 2018 16:42:01 +0200 Subject: [PATCH 151/499] Added documentation about message recorder --- messenger/message-recorder.rst | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 messenger/message-recorder.rst diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst new file mode 100644 index 00000000000..a4610546529 --- /dev/null +++ b/messenger/message-recorder.rst @@ -0,0 +1,69 @@ +.. index:: + single: Messenger; Record messages + +Record Events Produced by a Handler +=================================== + +In a example application there is a command (a CQRS message) named ``CreateUser``. +That command is handled by the ``CreateUserHandler``. The command handler creates +a ``User`` object, stores that object to a database and dispatches an ``UserCreatedEvent``. +That event is also a normal message but is handled by an *event* bus. + +There are many subscribers to the ``UserCreatedEvent``, one subscriber may send +a welcome email to the new user. Since we are using the ``DoctrineTransactionMiddleware`` +we wrap all database queries in one database transaction and rollback that transaction +if an exception is thrown. That would mean that if an exception is thrown when sending +the welcome email, then the user will not be created. + +The solution to this issue is to not dispatch the ``UserCreatedEvent`` in the +``CreateUserHandler`` but to just "record" the events. The recorded events will +be dispatched after ``DoctrineTransactionMiddleware`` has committed the transaction. + +To enable this, you simply just add the ``messenger.middleware.handles_recorded_messages`` +middleware. Make sure it is registered before ``DoctrineTransactionMiddleware`` +in the middleware chain. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/workflow.yaml + framework: + messenger: + default_bus: messenger.bus.command + buses: + messenger.bus.command: + middleware: + - messenger.middleware.validation + - messenger.middleware.handles_recorded_messages: ['@messenger.bus.event'] + # Doctrine transaction must be after handles_recorded_messages middleware + - app.doctrine_transaction_middleware: ['default'] + messenger.bus.event: + middleware: + - messenger.middleware.allow_no_handler + - messenger.middleware.validation + +.. code-block:: php + + use Doctrine\ORM\EntityManagerInterface; + use Symfony\Component\Messenger\MessageRecorderInterface; + + class CreateUserHandler + { + private $em; + private $eventRecorder; + + public function __construct(MessageRecorderInterface $eventRecorder, EntityManagerInterface $em) + { + $this->eventRecorder = $eventRecorder; + $this->em = $em; + } + + public function __invoke(CreateUser $command) + { + $user = new User($command->getUuid(), $command->getName(), $command->getEmail()); + $this->em->persist($user); + + $this->eventRecorder->record(new UserCreatedEvent($command->getUuid()); + } + } From fff86590b1c30f1164351326cd6005bd0ce0b6a2 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Thu, 5 Jul 2018 10:59:58 +0200 Subject: [PATCH 152/499] According to feedback --- messenger/message-recorder.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index a4610546529..4991d7c685b 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -4,15 +4,15 @@ Record Events Produced by a Handler =================================== -In a example application there is a command (a CQRS message) named ``CreateUser``. -That command is handled by the ``CreateUserHandler``. The command handler creates +In an example application there is a command (a CQRS message) named ``CreateUser``. +That command is handled by the ``CreateUserHandler`` which creates a ``User`` object, stores that object to a database and dispatches an ``UserCreatedEvent``. That event is also a normal message but is handled by an *event* bus. There are many subscribers to the ``UserCreatedEvent``, one subscriber may send a welcome email to the new user. Since we are using the ``DoctrineTransactionMiddleware`` we wrap all database queries in one database transaction and rollback that transaction -if an exception is thrown. That would mean that if an exception is thrown when sending +if an exception is thrown. That means that if an exception is thrown when sending the welcome email, then the user will not be created. The solution to this issue is to not dispatch the ``UserCreatedEvent`` in the @@ -27,7 +27,7 @@ in the middleware chain. .. code-block:: yaml - # config/packages/workflow.yaml + # config/packages/messenger.yaml framework: messenger: default_bus: messenger.bus.command @@ -45,6 +45,11 @@ in the middleware chain. .. code-block:: php + namespace App\Messenger\CommandHandler; + + use App\Entity\User; + use App\Messenger\Command\CreateUser; + use App\Messenger\Event\UserCreatedEvent; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Messenger\MessageRecorderInterface; From ca22c3cc26205e959061c31810ada12f923e7bc9 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Thu, 5 Jul 2018 11:02:44 +0200 Subject: [PATCH 153/499] a user --- messenger/message-recorder.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 4991d7c685b..741db9ec626 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -6,7 +6,7 @@ Record Events Produced by a Handler In an example application there is a command (a CQRS message) named ``CreateUser``. That command is handled by the ``CreateUserHandler`` which creates -a ``User`` object, stores that object to a database and dispatches an ``UserCreatedEvent``. +a ``User`` object, stores that object to a database and dispatches a ``UserCreatedEvent``. That event is also a normal message but is handled by an *event* bus. There are many subscribers to the ``UserCreatedEvent``, one subscriber may send From 84b81e3570268f911b316bb9a5cc33ae4a87eae1 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 26 Aug 2018 18:21:26 +0200 Subject: [PATCH 154/499] Added fixes --- messenger/message-recorder.rst | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 741db9ec626..92a52bd34d8 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -1,21 +1,23 @@ .. index:: single: Messenger; Record messages -Record Events Produced by a Handler -=================================== +Events Recorder: Handle Events After CommandHandler Is Done +=========================================================== -In an example application there is a command (a CQRS message) named ``CreateUser``. -That command is handled by the ``CreateUserHandler`` which creates -a ``User`` object, stores that object to a database and dispatches a ``UserCreatedEvent``. +Let's take the example of an application that has a command (a CQRS message) named +``CreateUser``. That command is handled by the ``CreateUserHandler`` which creates +a ``User`` object, stores that object to a database and dispatches a ``UserCreated`` event. That event is also a normal message but is handled by an *event* bus. -There are many subscribers to the ``UserCreatedEvent``, one subscriber may send -a welcome email to the new user. Since we are using the ``DoctrineTransactionMiddleware`` -we wrap all database queries in one database transaction and rollback that transaction -if an exception is thrown. That means that if an exception is thrown when sending -the welcome email, then the user will not be created. +There are many subscribers to the ``UserCreated`` event, one subscriber may send +a welcome email to the new user. We are using the ``DoctrineTransactionMiddleware`` +to wrap all database queries in one database transaction. -The solution to this issue is to not dispatch the ``UserCreatedEvent`` in the +**Problem:** If an exception is thrown when sending the welcome email, then the user +will not be created because the ``DoctrineTransactionMiddleware`` will rollback the +Doctrine transaction, in which the user has been created. + +**Solution:** The solution is to not dispatch the ``UserCreated`` event in the ``CreateUserHandler`` but to just "record" the events. The recorded events will be dispatched after ``DoctrineTransactionMiddleware`` has committed the transaction. @@ -69,6 +71,7 @@ in the middleware chain. $user = new User($command->getUuid(), $command->getName(), $command->getEmail()); $this->em->persist($user); + // "Record" this event to be processed later by "handles_recorded_messages". $this->eventRecorder->record(new UserCreatedEvent($command->getUuid()); } } From 30e958c35d4f2bc1fbeacb5b41a9ff44d4d7c25f Mon Sep 17 00:00:00 2001 From: Daryl Gubler Date: Sun, 24 Feb 2019 10:13:44 -0500 Subject: [PATCH 155/499] Explain HandleMessageInNewTransaction middleware The current PR is for HandleMessageInNewTransaction middleware instead of the original RecordsMessages middleware. This documentation covers the new middleware. --- messenger/message-recorder.rst | 101 +++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 92a52bd34d8..e4d494df98b 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -1,30 +1,62 @@ .. index:: - single: Messenger; Record messages + single: Messenger; Record messages; Transaction messages -Events Recorder: Handle Events After CommandHandler Is Done -=========================================================== +Transactional Messages: Handle Events After CommandHandler Is Done +================================================================== -Let's take the example of an application that has a command (a CQRS message) named -``CreateUser``. That command is handled by the ``CreateUserHandler`` which creates -a ``User`` object, stores that object to a database and dispatches a ``UserCreated`` event. -That event is also a normal message but is handled by an *event* bus. +A message handler can ``dispatch`` new messages during execution, to either the same or +a different bus (if the application has `multiple buses `_). +Any errors or exceptions that occur during this process can have unintended consequences, +such as: -There are many subscribers to the ``UserCreated`` event, one subscriber may send +- If using the ``DoctrineTransactionMiddleware`` and a dispatched message to the same bus + and an exception is thrown, then any database transactions in the original handler will + be rolled back. +- If the message is dispatched to a different bus, then the dispatched message can still + be handled even if the original handler encounters an exception. + +An Example ``SignUpUser`` Process +--------------------------------- + +Let's take the example of an application with both a *command* and an *event* bus. The application +dispatches a command named ``SignUpUser`` to the command bus. The command is handled by the +``SignUpUserHandler`` which creates a ``User`` object, stores that object to a database and +dispatches a ``UserSignedUp`` event to the event bus. + +There are many subscribers to the ``UserSignedUp`` event, one subscriber may send a welcome email to the new user. We are using the ``DoctrineTransactionMiddleware`` to wrap all database queries in one database transaction. -**Problem:** If an exception is thrown when sending the welcome email, then the user +**Problem 1:** If an exception is thrown when sending the welcome email, then the user will not be created because the ``DoctrineTransactionMiddleware`` will rollback the Doctrine transaction, in which the user has been created. -**Solution:** The solution is to not dispatch the ``UserCreated`` event in the -``CreateUserHandler`` but to just "record" the events. The recorded events will -be dispatched after ``DoctrineTransactionMiddleware`` has committed the transaction. +**Problem 2:** If an exception is thrown when saving the user to the database, the welcome +email is still sent. + +``HandleMessageInNewTransaction`` Middleware +-------------------------------------------- + +For many applications, the desired behavior is to have any messages dispatched by the handler +to `only` be handled after the handler finishes. This can be by using the +``HandleMessageInNewTransaction`` middleware and adding a ``Transaction`` stamp to +`the message Envelope `_. +This middleware enables us to add messages to a separate transaction that will only be +dispatched *after* the current message handler finishes. -To enable this, you simply just add the ``messenger.middleware.handles_recorded_messages`` +Referencing the above example, this means that the ``UserSignedUp`` event would not be handled +until *after* the ``SignUpUserHandler`` had completed and the new ``User`` was persisted to the +database. If the ``SignUpUserHandler`` encounters an exception, the ``UserSignedUp`` event will +never be handled and if an exception is thrown while sending the welcome email, the Doctrine +transaction will not be rolled back. + +To enable this, you need to add the ``handle_message_in_new_transaction`` middleware. Make sure it is registered before ``DoctrineTransactionMiddleware`` in the middleware chain. +**Note:** The ``handle_message_in_new_transaction`` middleware must be loaded for *all* of the +buses. For the example, the middleware must be loaded for both the command and event buses. + .. configuration-block:: .. code-block:: yaml @@ -33,45 +65,56 @@ in the middleware chain. framework: messenger: default_bus: messenger.bus.command + buses: messenger.bus.command: middleware: - - messenger.middleware.validation - - messenger.middleware.handles_recorded_messages: ['@messenger.bus.event'] - # Doctrine transaction must be after handles_recorded_messages middleware - - app.doctrine_transaction_middleware: ['default'] + - validation + - handle_message_in_new_transaction + - doctrine_transaction messenger.bus.event: + default_middleware: allow_no_handlers middleware: - - messenger.middleware.allow_no_handler - - messenger.middleware.validation + - validation + - handle_message_in_new_transaction + - doctrine_transaction + .. code-block:: php namespace App\Messenger\CommandHandler; use App\Entity\User; - use App\Messenger\Command\CreateUser; - use App\Messenger\Event\UserCreatedEvent; + use App\Messenger\Command\SignUpUser; + use App\Messenger\Event\UserSignedUp; use Doctrine\ORM\EntityManagerInterface; - use Symfony\Component\Messenger\MessageRecorderInterface; + use Symfony\Component\Messenger\Envelope; + use Symfony\Component\Messenger\Stamp\Transaction; + use Symfony\Component\Messenger\MessageBusInterface; - class CreateUserHandler + class SignUpUserHandler { private $em; - private $eventRecorder; + private $eventBus; - public function __construct(MessageRecorderInterface $eventRecorder, EntityManagerInterface $em) + public function __construct(MessageBusInterface $eventBus, EntityManagerInterface $em) { - $this->eventRecorder = $eventRecorder; + $this->eventBus = $eventBus; $this->em = $em; } - public function __invoke(CreateUser $command) + public function __invoke(SignUpUser $command) { $user = new User($command->getUuid(), $command->getName(), $command->getEmail()); $this->em->persist($user); - // "Record" this event to be processed later by "handles_recorded_messages". - $this->eventRecorder->record(new UserCreatedEvent($command->getUuid()); + // The Transaction stamp marks the event message to be handled + // only if this handler does not throw an exception. + + $event = new UserSignedUp($command->getUuid()); + $this->eventBus->dispatch( + (new Envelope($event)) + ->with(new Transaction()) + ); } } From 797f5307f442c6e821fb9f9f0267693df817d9ba Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 17 Mar 2019 11:41:48 +0100 Subject: [PATCH 156/499] Minor updates --- messenger/message-recorder.rst | 63 ++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index e4d494df98b..3d92a04a23f 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -9,9 +9,8 @@ a different bus (if the application has `multiple buses `_. -This middleware enables us to add messages to a separate transaction that will only be -dispatched *after* the current message handler finishes. +``DispatchAfterCurrentBusMiddleware`` middleware and adding a ``DispatchAfterCurrentBusStamp`` +stamp to `the message Envelope `_. Referencing the above example, this means that the ``UserSignedUp`` event would not be handled until *after* the ``SignUpUserHandler`` had completed and the new ``User`` was persisted to the @@ -50,11 +47,12 @@ database. If the ``SignUpUserHandler`` encounters an exception, the ``UserSigned never be handled and if an exception is thrown while sending the welcome email, the Doctrine transaction will not be rolled back. -To enable this, you need to add the ``handle_message_in_new_transaction`` -middleware. Make sure it is registered before ``DoctrineTransactionMiddleware`` +The ``dispatch_after_current_bus`` middleware is enabled by default. It is configured as the +first middleware on all busses. When doing a highly custom or special configuration, then make +sure ``dispatch_after_current_bus`` is registered before ``doctrine_transaction`` in the middleware chain. -**Note:** The ``handle_message_in_new_transaction`` middleware must be loaded for *all* of the +**Note:** The ``dispatch_after_current_bus`` middleware must be loaded for *all* of the buses. For the example, the middleware must be loaded for both the command and event buses. .. configuration-block:: @@ -70,13 +68,11 @@ buses. For the example, the middleware must be loaded for both the command and e messenger.bus.command: middleware: - validation - - handle_message_in_new_transaction - doctrine_transaction messenger.bus.event: default_middleware: allow_no_handlers middleware: - validation - - handle_message_in_new_transaction - doctrine_transaction @@ -89,7 +85,7 @@ buses. For the example, the middleware must be loaded for both the command and e use App\Messenger\Event\UserSignedUp; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Messenger\Envelope; - use Symfony\Component\Messenger\Stamp\Transaction; + use Symfony\Component\Messenger\Stamp\DispatchAfterCurrentBusStamp; use Symfony\Component\Messenger\MessageBusInterface; class SignUpUserHandler @@ -108,13 +104,44 @@ buses. For the example, the middleware must be loaded for both the command and e $user = new User($command->getUuid(), $command->getName(), $command->getEmail()); $this->em->persist($user); - // The Transaction stamp marks the event message to be handled + // The DispatchAfterCurrentBusStamp marks the event message to be handled // only if this handler does not throw an exception. $event = new UserSignedUp($command->getUuid()); $this->eventBus->dispatch( (new Envelope($event)) - ->with(new Transaction()) + ->with(new DispatchAfterCurrentBusStamp()) ); } } + +.. code-block:: php + + namespace App\Messenger\EventSubscriber; + + use App\Entity\User; + use App\Messenger\Event\UserSignedUp; + use Doctrine\ORM\EntityManagerInterface; + + class WhenUserSignedUpThenSendWelcomeEmail + { + private $em; + private $mailer; + + public function __construct(MyMailer $mailer, EntityManagerInterface $em) + { + $this->mailer = $mailer; + $this->em = $em; + } + + public function __invoke(UserSignedUp $eent) + { + $user = $this->em->getRepository(User::class)->find(new User($event->getUuid())); + + $this->mailer->sendWelcomeEmail($user); + } + } + +**Note:** If ``WhenUserSignedUpThenSendWelcomeEmail`` throws an exception, that exception +will be wrapped into a ``DelayedMessageHandlingException``. Using ``DelayedMessageHandlingException::getExceptions`` +will give you all exceptions that are thrown while handing a message with the ``DispatchAfterCurrentBusStamp``. From 06ec8a41691dacb57c2266b214335e83a6d8ebaa Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Mon, 8 Apr 2019 20:52:51 +0200 Subject: [PATCH 157/499] Added PHP and XML config --- messenger/message-recorder.rst | 43 +++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 3d92a04a23f..e2f8fb97810 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -53,7 +53,7 @@ sure ``dispatch_after_current_bus`` is registered before ``doctrine_transaction` in the middleware chain. **Note:** The ``dispatch_after_current_bus`` middleware must be loaded for *all* of the -buses. For the example, the middleware must be loaded for both the command and event buses. +buses. For the example, the middleware must be loaded for both the command and event bus. .. configuration-block:: @@ -75,6 +75,47 @@ buses. For the example, the middleware must be loaded for both the command and e - validation - doctrine_transaction + .. code-block:: xml + + + + + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/cache.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'default_bus' => 'messenger.bus.command', + 'buses' => [ + 'messenger.bus.command' => [ + 'middleware' => ['validation', 'doctrine_transaction'], + ], + 'messenger.bus.event' => [ + 'default_middleware' => 'allow_no_handlers', + 'middleware' => ['validation', 'doctrine_transaction'], + ], + ], + ], + ]); .. code-block:: php From cfa56f7c1e36a93d23a49f3476a4d81aba65f2e9 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 8 Apr 2019 21:37:24 +0200 Subject: [PATCH 158/499] Update messenger/message-recorder.rst Co-Authored-By: Nyholm --- messenger/message-recorder.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index e2f8fb97810..d6aff9080ff 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -1,7 +1,7 @@ .. index:: single: Messenger; Record messages; Transaction messages -Transactional Messages: Handle Events After CommandHandler Is Done +Transactional Messages: Handle Events After CommandHandler is Done ================================================================== A message handler can ``dispatch`` new messages during execution, to either the same or From c1cef9e05686308032bec4009aed6352ede06f23 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 8 Apr 2019 21:38:11 +0200 Subject: [PATCH 159/499] Update messenger/message-recorder.rst Co-Authored-By: Nyholm --- messenger/message-recorder.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index d6aff9080ff..8de5aa5d01c 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -77,7 +77,7 @@ buses. For the example, the middleware must be loaded for both the command and e .. code-block:: xml - + Date: Mon, 8 Apr 2019 21:40:06 +0200 Subject: [PATCH 160/499] Update messenger/message-recorder.rst Co-Authored-By: Nyholm --- messenger/message-recorder.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 8de5aa5d01c..bf6c8899601 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -101,7 +101,7 @@ buses. For the example, the middleware must be loaded for both the command and e .. code-block:: php - // config/packages/cache.php + // config/packages/messenger.php $container->loadFromExtension('framework', [ 'messenger' => [ 'default_bus' => 'messenger.bus.command', From 3e99663b5f8a28947e843c243130f76f317395a3 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 8 Apr 2019 21:40:30 +0200 Subject: [PATCH 161/499] Update messenger/message-recorder.rst Co-Authored-By: Nyholm --- messenger/message-recorder.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index bf6c8899601..8b7a27af6dd 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -175,7 +175,7 @@ buses. For the example, the middleware must be loaded for both the command and e $this->em = $em; } - public function __invoke(UserSignedUp $eent) + public function __invoke(UserSignedUp $event) { $user = $this->em->getRepository(User::class)->find(new User($event->getUuid())); From ec3e1d706f0e8c2041206acbdb799ae671caae13 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Mon, 8 Apr 2019 22:01:45 +0200 Subject: [PATCH 162/499] updates according to feedback --- messenger/message-recorder.rst | 52 ++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 8b7a27af6dd..63018e4125f 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -14,15 +14,15 @@ such as: - If the message is dispatched to a different bus, then the dispatched message can still be handled even if the original handler encounters an exception. -An Example ``SignUpUser`` Process ---------------------------------- +An Example ``RegisterUser`` Process +----------------------------------- Let's take the example of an application with both a *command* and an *event* bus. The application -dispatches a command named ``SignUpUser`` to the command bus. The command is handled by the -``SignUpUserHandler`` which creates a ``User`` object, stores that object to a database and -dispatches a ``UserSignedUp`` event to the event bus. +dispatches a command named ``RegisterUser`` to the command bus. The command is handled by the +``RegisterUserHandler`` which creates a ``User`` object, stores that object to a database and +dispatches a ``UserRegistered`` event to the event bus. -There are many subscribers to the ``UserSignedUp`` event, one subscriber may send +There are many subscribers to the ``UserRegistered`` event, one subscriber may send a welcome email to the new user. We are using the ``DoctrineTransactionMiddleware`` to wrap all database queries in one database transaction. @@ -41,9 +41,9 @@ to `only` be handled after the handler finishes. This can be by using the ``DispatchAfterCurrentBusMiddleware`` middleware and adding a ``DispatchAfterCurrentBusStamp`` stamp to `the message Envelope `_. -Referencing the above example, this means that the ``UserSignedUp`` event would not be handled -until *after* the ``SignUpUserHandler`` had completed and the new ``User`` was persisted to the -database. If the ``SignUpUserHandler`` encounters an exception, the ``UserSignedUp`` event will +Referencing the above example, this means that the ``UserRegistered`` event would not be handled +until *after* the ``RegisterUserHandler`` had completed and the new ``User`` was persisted to the +database. If the ``RegisterUserHandler`` encounters an exception, the ``UserRegistered`` event will never be handled and if an exception is thrown while sending the welcome email, the Doctrine transaction will not be rolled back. @@ -122,17 +122,17 @@ buses. For the example, the middleware must be loaded for both the command and e namespace App\Messenger\CommandHandler; use App\Entity\User; - use App\Messenger\Command\SignUpUser; - use App\Messenger\Event\UserSignedUp; + use App\Messenger\Command\RegisterUser; + use App\Messenger\Event\UserRegistered; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Stamp\DispatchAfterCurrentBusStamp; use Symfony\Component\Messenger\MessageBusInterface; - class SignUpUserHandler + class RegisterUserHandler { - private $em; private $eventBus; + private $em; public function __construct(MessageBusInterface $eventBus, EntityManagerInterface $em) { @@ -140,7 +140,7 @@ buses. For the example, the middleware must be loaded for both the command and e $this->em = $em; } - public function __invoke(SignUpUser $command) + public function __invoke(RegisterUser $command) { $user = new User($command->getUuid(), $command->getName(), $command->getEmail()); $this->em->persist($user); @@ -148,7 +148,7 @@ buses. For the example, the middleware must be loaded for both the command and e // The DispatchAfterCurrentBusStamp marks the event message to be handled // only if this handler does not throw an exception. - $event = new UserSignedUp($command->getUuid()); + $event = new UserRegistered($command->getUuid()); $this->eventBus->dispatch( (new Envelope($event)) ->with(new DispatchAfterCurrentBusStamp()) @@ -161,28 +161,32 @@ buses. For the example, the middleware must be loaded for both the command and e namespace App\Messenger\EventSubscriber; use App\Entity\User; - use App\Messenger\Event\UserSignedUp; + use App\Messenger\Event\UserRegistered; use Doctrine\ORM\EntityManagerInterface; + use Symfony\Component\Mailer\MailerInterface; + use Symfony\Component\Mime\RawMessage; - class WhenUserSignedUpThenSendWelcomeEmail + class WhenUserRegisteredThenSendWelcomeEmail { - private $em; private $mailer; + private $em; - public function __construct(MyMailer $mailer, EntityManagerInterface $em) + public function __construct(MailerInterface $mailer, EntityManagerInterface $em) { $this->mailer = $mailer; $this->em = $em; } - public function __invoke(UserSignedUp $event) + public function __invoke(UserRegistered $event) { $user = $this->em->getRepository(User::class)->find(new User($event->getUuid())); - $this->mailer->sendWelcomeEmail($user); + $this->mailer->send(new RawMessage('Welcome '.$user->getFirstName())); } } -**Note:** If ``WhenUserSignedUpThenSendWelcomeEmail`` throws an exception, that exception -will be wrapped into a ``DelayedMessageHandlingException``. Using ``DelayedMessageHandlingException::getExceptions`` -will give you all exceptions that are thrown while handing a message with the ``DispatchAfterCurrentBusStamp``. +.. note:: + + If ``WhenUserRegisteredThenSendWelcomeEmail`` throws an exception, that exception + will be wrapped into a ``DelayedMessageHandlingException``. Using ``DelayedMessageHandlingException::getExceptions`` + will give you all exceptions that are thrown while handing a message with the ``DispatchAfterCurrentBusStamp``. From 0d12880cf4a956283d3f4134d2cedfc5220687cf Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sun, 28 Apr 2019 09:14:00 +0200 Subject: [PATCH 163/499] minor updates according to feedback --- messenger/message-recorder.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 63018e4125f..2a95e5b8bfc 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -11,8 +11,8 @@ such as: - If using the ``DoctrineTransactionMiddleware`` and a dispatched message throws an exception, then any database transactions in the original handler will be rolled back. -- If the message is dispatched to a different bus, then the dispatched message can still - be handled even if the original handler encounters an exception. +- If the message is dispatched to a different bus, then dispatched message will be + handled even if the current handler throws an exception. An Example ``RegisterUser`` Process ----------------------------------- @@ -68,12 +68,10 @@ buses. For the example, the middleware must be loaded for both the command and e messenger.bus.command: middleware: - validation - - doctrine_transaction messenger.bus.event: default_middleware: allow_no_handlers middleware: - validation - - doctrine_transaction .. code-block:: xml @@ -153,6 +151,8 @@ buses. For the example, the middleware must be loaded for both the command and e (new Envelope($event)) ->with(new DispatchAfterCurrentBusStamp()) ); + + // ... } } From 599d10b23fbc7cefdb4d3bf71acd2e6e6ec3ca54 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Fri, 24 May 2019 10:13:42 -0400 Subject: [PATCH 164/499] minor reorg of new DispatchAfterCurrentBusMiddleware --- messenger/message-recorder.rst | 104 +++++++-------------------------- 1 file changed, 21 insertions(+), 83 deletions(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 2a95e5b8bfc..4dd9c79e35e 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -1,7 +1,7 @@ .. index:: single: Messenger; Record messages; Transaction messages -Transactional Messages: Handle Events After CommandHandler is Done +Transactional Messages: Handle New Messages After Handling is Done ================================================================== A message handler can ``dispatch`` new messages during execution, to either the same or @@ -11,8 +11,8 @@ such as: - If using the ``DoctrineTransactionMiddleware`` and a dispatched message throws an exception, then any database transactions in the original handler will be rolled back. -- If the message is dispatched to a different bus, then dispatched message will be - handled even if the current handler throws an exception. +- If the message is dispatched to a different bus, then the dispatched message will + be handled even if some code later in the current handler throws an exception. An Example ``RegisterUser`` Process ----------------------------------- @@ -20,9 +20,9 @@ An Example ``RegisterUser`` Process Let's take the example of an application with both a *command* and an *event* bus. The application dispatches a command named ``RegisterUser`` to the command bus. The command is handled by the ``RegisterUserHandler`` which creates a ``User`` object, stores that object to a database and -dispatches a ``UserRegistered`` event to the event bus. +dispatches a ``UserRegistered`` message to the event bus. -There are many subscribers to the ``UserRegistered`` event, one subscriber may send +There are many handlers to the ``UserRegistered`` message, one handler may send a welcome email to the new user. We are using the ``DoctrineTransactionMiddleware`` to wrap all database queries in one database transaction. @@ -33,88 +33,14 @@ Doctrine transaction, in which the user has been created. **Problem 2:** If an exception is thrown when saving the user to the database, the welcome email is still sent because it is handled asynchronously. -``DispatchAfterCurrentBusMiddleware`` Middleware ------------------------------------------------- +DispatchAfterCurrentBusMiddleware Middleware +-------------------------------------------- -For many applications, the desired behavior is to have any messages dispatched by the handler -to `only` be handled after the handler finishes. This can be by using the +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 using the ``DispatchAfterCurrentBusMiddleware`` middleware and adding a ``DispatchAfterCurrentBusStamp`` stamp to `the message Envelope `_. -Referencing the above example, this means that the ``UserRegistered`` event would not be handled -until *after* the ``RegisterUserHandler`` had completed and the new ``User`` was persisted to the -database. If the ``RegisterUserHandler`` encounters an exception, the ``UserRegistered`` event will -never be handled and if an exception is thrown while sending the welcome email, the Doctrine -transaction will not be rolled back. - -The ``dispatch_after_current_bus`` middleware is enabled by default. It is configured as the -first middleware on all busses. When doing a highly custom or special configuration, then make -sure ``dispatch_after_current_bus`` is registered before ``doctrine_transaction`` -in the middleware chain. - -**Note:** The ``dispatch_after_current_bus`` middleware must be loaded for *all* of the -buses. For the example, the middleware must be loaded for both the command and event bus. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - default_bus: messenger.bus.command - - buses: - messenger.bus.command: - middleware: - - validation - messenger.bus.event: - default_middleware: allow_no_handlers - middleware: - - validation - - .. code-block:: xml - - - - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'default_bus' => 'messenger.bus.command', - 'buses' => [ - 'messenger.bus.command' => [ - 'middleware' => ['validation', 'doctrine_transaction'], - ], - 'messenger.bus.event' => [ - 'default_middleware' => 'allow_no_handlers', - 'middleware' => ['validation', 'doctrine_transaction'], - ], - ], - ], - ]); - .. code-block:: php namespace App\Messenger\CommandHandler; @@ -185,8 +111,20 @@ buses. For the example, the middleware must be loaded for both the command and e } } +This means that the ``UserRegistered`` message would not be handled +until *after* the ``RegisterUserHandler`` had completed and the new ``User`` was persisted to the +database. If the ``RegisterUserHandler`` encounters an exception, the ``UserRegistered`` event will +never be handled. And if an exception is thrown while sending the welcome email, the Doctrine +transaction will not be rolled back. + .. note:: If ``WhenUserRegisteredThenSendWelcomeEmail`` throws an exception, that exception will be wrapped into a ``DelayedMessageHandlingException``. Using ``DelayedMessageHandlingException::getExceptions`` will give you all exceptions that are thrown while handing a message with the ``DispatchAfterCurrentBusStamp``. + +The ``dispatch_after_current_bus`` middleware is enabled by default. If you're +configuring your middleware manually, be sure to register +``dispatch_after_current_bus`` before ``doctrine_transaction`` in the middleware +chain. Also, the ``dispatch_after_current_bus`` middleware must be loaded for *all* of +the buses being used. From 27c0f9d480c996618e2811e5bdfe9b8b6111efc1 Mon Sep 17 00:00:00 2001 From: Vincent Touzet Date: Tue, 9 Apr 2019 13:21:08 +0200 Subject: [PATCH 165/499] [Messenger] Describe the doctrine tranport --- messenger/doctrine-transport.rst | 214 +++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 messenger/doctrine-transport.rst diff --git a/messenger/doctrine-transport.rst b/messenger/doctrine-transport.rst new file mode 100644 index 00000000000..ec9a9f2f86d --- /dev/null +++ b/messenger/doctrine-transport.rst @@ -0,0 +1,214 @@ +.. index:: + single: Messenger; Use Doctrine as Transport + +Use Doctrine as transport +========================= + +The Messenger component comes with a Doctrine transport. This lets Doctrine handle the storage of your messages. To use it you need to define the transport as the following: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + transports: + doctrine: doctrine://default + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'transports' => [ + 'doctrine' => 'doctrine://default', + ], + ], + ]); + +The format of the DSN is ``doctrine://``. The connection name is the name you used in the doctrine configuration. If you only use one connection then use ``default``. + +If you have multiple Doctrine connections defined you can choose the desired one. If you have a connection named ``legacy`` the you should use the following DSN : ``doctrine://legacy``. + +Customize Table Name +-------------------- + +By default the transport will create a table named ``messenger_messages`` but you can configure it per transport: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + transports: + doctrine: + dsn: doctrine://default?table_name=custom_table_name_for_messages + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'transports' => [ + 'doctrine' => [ + 'dsn' => 'doctrine://default?table_name=custom_table_name_for_messages', + ], + ], + ], + ]); + +Use the same table for different messages +----------------------------------------- + +If you want to store the messages in the same table you can configure the ``queue_name`` option. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + transports: + doctrine: + dsn: doctrine://default?queue_name=custom_queue + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'transports' => [ + 'doctrine' => 'doctrine://default?queue_name=custom_queue', + ], + ], + ]); + +Available options +----------------- + +The transport can be configured via DSN or as options. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + transports: + doctrine_short: doctrine://default?queue_name=custom_queue + doctrine_full: + dsn: doctrine://default + options: + queue_name: custom_queue + + .. code-block:: xml + + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'transports' => [ + 'doctrine_short' => 'dsn' => 'doctrine://default?queue_name=custom_queue', + 'doctrine_full' => [ + 'dsn' => 'doctrine://default', + 'options' => [ + 'queue_name' => 'custom_queue' + ] + ], + ], + ], + ]); + +Options defined in the options transport takes precedence over the ones defined in the DSN. + ++-------------------+--------------------------------------------------------------------------------------------------------------------------+--------------------+ +| Option + Description | Default | ++-------------------+--------------------------------------------------------------------------------------------------------------------------+--------------------+ +| table_name | Name of the table | messenger_messages | +| queue_name | Name of the queue | default | +| redeliver_timeout | Timeout before redeliver messages still in handling state (i.e: delivered_at is not null and message is still in table). | 3600 | +| auto_setup | Whether the table should be created automatically during send / get. | true | ++-------------------+--------------------------------------------------------------------------------------------------------------------------+--------------------+ From a3d8a57df9206eacc82500279adbbbeb11b47e08 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Wed, 22 May 2019 16:49:39 +0200 Subject: [PATCH 166/499] [Intl] Remove \"Writing and Reading Resource Bundles\" section --- components/intl.rst | 155 +------------------------------------------- 1 file changed, 1 insertion(+), 154 deletions(-) diff --git a/components/intl.rst b/components/intl.rst index 1acef5e809d..3e0f8a03208 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -52,160 +52,6 @@ replace the intl classes: Composer automatically exposes these classes in the global namespace. -Writing and Reading Resource Bundles ------------------------------------- - -The :phpclass:`ResourceBundle` class is not currently supported by this component. -Instead, it includes a set of readers and writers for reading and writing -arrays (or array-like objects) from/to resource bundle files. The following -classes are supported: - -* `TextBundleWriter`_ -* `PhpBundleWriter`_ -* `BinaryBundleReader`_ -* `PhpBundleReader`_ -* `BufferedBundleReader`_ -* `StructuredBundleReader`_ - -Continue reading if you are interested in how to use these classes. Otherwise -skip this section and jump to `Accessing ICU Data`_. - -TextBundleWriter -~~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Writer\\TextBundleWriter` -writes an array or an array-like object to a plain-text resource bundle. The -resulting .txt file can be converted to a binary .res file with the -:class:`Symfony\\Component\\Intl\\ResourceBundle\\Compiler\\BundleCompiler` -class:: - - use Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompiler; - use Symfony\Component\Intl\ResourceBundle\Writer\TextBundleWriter; - - $writer = new TextBundleWriter(); - $writer->write('/path/to/bundle', 'en', [ - 'Data' => [ - 'entry1', - 'entry2', - // ... - ], - ]); - - $compiler = new BundleCompiler(); - $compiler->compile('/path/to/bundle', '/path/to/binary/bundle'); - -The command "genrb" must be available for the -:class:`Symfony\\Component\\Intl\\ResourceBundle\\Compiler\\BundleCompiler` to -work. If the command is located in a non-standard location, you can pass its -path to the -:class:`Symfony\\Component\\Intl\\ResourceBundle\\Compiler\\BundleCompiler` -constructor. - -PhpBundleWriter -~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Writer\\PhpBundleWriter` -writes an array or an array-like object to a .php resource bundle:: - - use Symfony\Component\Intl\ResourceBundle\Writer\PhpBundleWriter; - - $writer = new PhpBundleWriter(); - $writer->write('/path/to/bundle', 'en', [ - 'Data' => [ - 'entry1', - 'entry2', - // ... - ], - ]); - -BinaryBundleReader -~~~~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\BinaryBundleReader` -reads binary resource bundle files and returns an array or an array-like object. -This class currently only works with the `intl extension`_ installed:: - - use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader; - - $reader = new BinaryBundleReader(); - $data = $reader->read('/path/to/bundle', 'en'); - - var_dump($data['Data']['entry1']); - -PhpBundleReader -~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\PhpBundleReader` -reads resource bundles from .php files and returns an array or an array-like -object:: - - use Symfony\Component\Intl\ResourceBundle\Reader\PhpBundleReader; - - $reader = new PhpBundleReader(); - $data = $reader->read('/path/to/bundle', 'en'); - - var_dump($data['Data']['entry1']); - -BufferedBundleReader -~~~~~~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\BufferedBundleReader` -wraps another reader, but keeps the last N reads in a buffer, where N is a -buffer size passed to the constructor:: - - use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader; - use Symfony\Component\Intl\ResourceBundle\Reader\BufferedBundleReader; - - $reader = new BufferedBundleReader(new BinaryBundleReader(), 10); - - // actually reads the file - $data = $reader->read('/path/to/bundle', 'en'); - - // returns data from the buffer - $data = $reader->read('/path/to/bundle', 'en'); - - // actually reads the file - $data = $reader->read('/path/to/bundle', 'fr'); - -StructuredBundleReader -~~~~~~~~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\StructuredBundleReader` -wraps another reader and offers a -:method:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\StructuredBundleReaderInterface::readEntry` -method for reading an entry of the resource bundle without having to worry -whether array keys are set or not. If a path cannot be resolved, ``null`` is -returned:: - - use Symfony\Component\Intl\ResourceBundle\Reader\BinaryBundleReader; - use Symfony\Component\Intl\ResourceBundle\Reader\StructuredBundleReader; - - $reader = new StructuredBundleReader(new BinaryBundleReader()); - - $data = $reader->read('/path/to/bundle', 'en'); - - // produces an error if the key "Data" does not exist - var_dump($data['Data']['entry1']); - - // returns null if the key "Data" does not exist - var_dump($reader->readEntry('/path/to/bundle', 'en', ['Data', 'entry1'])); - -Additionally, the -:method:`Symfony\\Component\\Intl\\ResourceBundle\\Reader\\StructuredBundleReaderInterface::readEntry` -method resolves fallback locales. For example, the fallback locale of "en_GB" is -"en". For single-valued entries (strings, numbers etc.), the entry will be read -from the fallback locale if it cannot be found in the more specific locale. For -multi-valued entries (arrays), the values of the more specific and the fallback -locale will be merged. In order to suppress this behavior, the last parameter -``$fallback`` can be set to ``false``:: - - var_dump($reader->readEntry( - '/path/to/bundle', - 'en', - ['Data', 'entry1'], - false - )); - Accessing ICU Data ------------------ @@ -442,6 +288,7 @@ Learn more /reference/forms/types/currency /reference/forms/types/language /reference/forms/types/locale + /reference/forms/types/timezone .. _Packagist: https://packagist.org/packages/symfony/intl .. _Icu component: https://packagist.org/packages/symfony/icu From bfccca2d3021e356257b6f73021c546dd2daa4d4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 28 May 2019 09:53:51 +0200 Subject: [PATCH 167/499] Minor tweaks --- messenger/message-recorder.rst | 75 ++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 4dd9c79e35e..8ac3039b503 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -4,44 +4,46 @@ Transactional Messages: Handle New Messages After Handling is Done ================================================================== -A message handler can ``dispatch`` new messages during execution, to either the same or -a different bus (if the application has `multiple buses `_). -Any errors or exceptions that occur during this process can have unintended consequences, -such as: - -- If using the ``DoctrineTransactionMiddleware`` and a dispatched message throws an exception, - then any database transactions in the original handler will be rolled back. -- If the message is dispatched to a different bus, then the dispatched message will - be handled even if some code later in the current handler throws an exception. +A message handler can ``dispatch`` new messages during execution, to either the +same or a different bus (if the application has +`multiple buses `_). Any errors or exceptions that +occur during this process can have unintended consequences, such as: + +- If using the ``DoctrineTransactionMiddleware`` and a dispatched message throws + an exception, then any database transactions in the original handler will be + rolled back. +- If the message is dispatched to a different bus, then the dispatched message + will be handled even if some code later in the current handler throws an + exception. An Example ``RegisterUser`` Process ----------------------------------- -Let's take the example of an application with both a *command* and an *event* bus. The application -dispatches a command named ``RegisterUser`` to the command bus. The command is handled by the -``RegisterUserHandler`` which creates a ``User`` object, stores that object to a database and -dispatches a ``UserRegistered`` message to the event bus. +Let's take the example of an application with both a *command* and an *event* +bus. The application dispatches a command named ``RegisterUser`` to the command +bus. The command is handled by the ``RegisterUserHandler`` which creates a +``User`` object, stores that object to a database and dispatches a +``UserRegistered`` message to the event bus. There are many handlers to the ``UserRegistered`` message, one handler may send a welcome email to the new user. We are using the ``DoctrineTransactionMiddleware`` to wrap all database queries in one database transaction. -**Problem 1:** If an exception is thrown when sending the welcome email, then the user -will not be created because the ``DoctrineTransactionMiddleware`` will rollback the -Doctrine transaction, in which the user has been created. +**Problem 1:** If an exception is thrown when sending the welcome email, then +the user will not be created because the ``DoctrineTransactionMiddleware`` will +rollback the Doctrine transaction, in which the user has been created. -**Problem 2:** If an exception is thrown when saving the user to the database, the welcome -email is still sent because it is handled asynchronously. +**Problem 2:** If an exception is thrown when saving the user to the database, +the welcome email is still sent because it is handled asynchronously. 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 using the -``DispatchAfterCurrentBusMiddleware`` middleware and adding a ``DispatchAfterCurrentBusStamp`` -stamp to `the message Envelope `_. - -.. code-block:: php +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 +using the ``DispatchAfterCurrentBusMiddleware`` and adding a +``DispatchAfterCurrentBusStamp`` stamp to +`the message Envelope `_:: namespace App\Messenger\CommandHandler; @@ -111,20 +113,23 @@ stamp to `the message Envelope Date: Fri, 24 May 2019 16:43:17 +0200 Subject: [PATCH 168/499] Mentioned the extraction of translation contents from PHP files --- reference/configuration/twig.rst | 2 ++ translation.rst | 23 +++++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index 04dbb249bf0..1e801569f28 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -301,6 +301,8 @@ on. Set it to ``0`` to disable all the optimizations. You can even enable or disable these optimizations selectively, as explained in the Twig documentation about `the optimizer extension`_. +.. _config-twig-default-path: + default_path ~~~~~~~~~~~~ diff --git a/translation.rst b/translation.rst index ac859742c55..3b1692c3755 100644 --- a/translation.rst +++ b/translation.rst @@ -357,23 +357,27 @@ with these tasks: .. code-block:: terminal - # updates the French translation file with the missing strings found in templates/ + # updates the French translation file with the missing strings for that locale $ php bin/console translation:update --dump-messages --force fr - # updates the English translation file with the missing strings found in AppBundle - $ php bin/console translation:update --dump-messages --force en AppBundle +The ``translation:update`` command looks for missing translations in: + +* Templates stored in the ``templates/`` directory (or any other directory + defined in the :ref:`twig.default_path ` and + :ref:`twig.paths ` config options); +* 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 the translation files, remove the ``--force`` option from the command above. -.. tip:: - - If you need to extract translation strings from other sources, such as - controllers, forms and flash messages, consider using the more advanced - third-party `TranslationBundle`_. - .. _translation-resource-locations: Translation Resource/File Names and Locations @@ -564,4 +568,3 @@ Learn more .. _`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 Behavior`: https://github.com/KnpLabs/DoctrineBehaviors -.. _`TranslationBundle`: https://github.com/php-translation/symfony-bundle From 4cfe39bad8fff7cfeb2b255a76dc53645b32d055 Mon Sep 17 00:00:00 2001 From: Stephen Clouse Date: Thu, 9 May 2019 02:08:00 -0500 Subject: [PATCH 169/499] Document Redis Sentinel support for Cache --- components/cache/adapters/redis_adapter.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/cache/adapters/redis_adapter.rst b/components/cache/adapters/redis_adapter.rst index 987abb5e38c..15e78a685e4 100644 --- a/components/cache/adapters/redis_adapter.rst +++ b/components/cache/adapters/redis_adapter.rst @@ -94,10 +94,21 @@ Below are common examples of valid DSNs showing a combination of available value 'redis:?host[localhost]&host[localhost:6379]&host[/var/run/redis.sock:]&auth=my-password&redis_cluster=1' ); + // Redis Sentinel is also supported in the same way + // set the redis_sentinel parameter to the name of your service group + // Sentinel support also requires the Predis library + RedisAdapter::createConnection( + '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 From 1f31fae866b46bd5c4519c87dbfed654b091c7e7 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 28 May 2019 12:26:41 +0200 Subject: [PATCH 170/499] Minor reword --- components/cache/adapters/redis_adapter.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/cache/adapters/redis_adapter.rst b/components/cache/adapters/redis_adapter.rst index 15e78a685e4..53b28c58466 100644 --- a/components/cache/adapters/redis_adapter.rst +++ b/components/cache/adapters/redis_adapter.rst @@ -94,9 +94,10 @@ Below are common examples of valid DSNs showing a combination of available value 'redis:?host[localhost]&host[localhost:6379]&host[/var/run/redis.sock:]&auth=my-password&redis_cluster=1' ); - // Redis Sentinel is also supported in the same way - // set the redis_sentinel parameter to the name of your service group - // Sentinel support also requires the Predis library +`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:: + RedisAdapter::createConnection( 'redis:?host[redis1:26379]&host[redis2:26379]&host[redis3:26379]&redis_sentinel=mymaster' ); @@ -195,3 +196,4 @@ Available Options .. _`Predis`: https://packagist.org/packages/predis/predis .. _`Predis Connection Parameters`: https://github.com/nrk/predis/wiki/Connection-Parameters#list-of-connection-parameters .. _`TCP-keepalive`: https://redis.io/topics/clients#tcp-keepalive +.. _`Redis Sentinel`: https://redis.io/topics/sentinel From b87a85e8fd35b5ae97b355ec6ee0ec78e84c42dc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 28 May 2019 17:25:51 +0200 Subject: [PATCH 171/499] Documented more missing Timezones features --- components/intl.rst | 51 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/components/intl.rst b/components/intl.rst index 3e0f8a03208..a10d8102a8e 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -247,7 +247,8 @@ You can also check if a given currency code is valid:: Timezones ~~~~~~~~~ -The ``Timezones`` class provides access to the name and values of all timezones:: +The ``Timezones`` class provides several utilities related to timezones. First, +you can get the name and values of all timezones in all languages:: use Symfony\Component\Intl\Timezones; @@ -269,7 +270,51 @@ which defaults to the current default locale:: $timezone = Timezones::getName('Africa/Nairobi', 'de'); // => 'Ostafrikanische Zeit (Nairobi)' -You can also check if a given timezone ID is valid:: +You can also get all the timezones that exist in a given country. The +``forCountryCode()`` method returns one or more timezone IDs, which you can +translate into any locale with the ``getName()`` method shown earlier:: + + // unlike language codes, country codes are always uppercase (CL = Chile) + $timezones = Timezones::forCountryCode('CL'); + // => ['America/Punta_Arenas', 'America/Santiago', 'Pacific/Easter'] + +The reverse lookup is also possible thanks to the ``getCountryCode()`` method, +which returns the code of the country where the given timezone ID belongs to:: + + $countryCode = Timezones::getCountryCode('America/Vancouver') + // => $countryCode = 'CA' (CA = Canada) + +The `UTC/GMT time offsets`_ of all timezones are provided by ``getRawOffset()`` +(which returns an integer representing the offset in seconds) and +``getGmtOffset()`` (which returns a string representation of the offset to +display it to users):: + + $offset = Timezones::getRawOffset('Etc/UTC'); // $offset = 0 + $offset = Timezones::getRawOffset('America/Buenos_Aires'); // $offset = -10800 + $offset = Timezones::getRawOffset('Asia/Katmandu'); // $offset = 20700 + + $offset = Timezones::getGmtOffset('Etc/UTC'); // $offset = 'GMT+00:00' + $offset = Timezones::getGmtOffset('America/Buenos_Aires'); // $offset = 'GMT-03:00' + $offset = Timezones::getGmtOffset('Asia/Katmandu'); // $offset = 'GMT+05:45' + +The timezone offset can vary in time because of the `daylight saving time (DST)`_ +practice. By default these methods use the ``time()`` PHP function to get the +current timezone offset value, but you can pass a timestamp as their second +arguments to get the offset at any given point in time:: + + // In 2019, the DST period in Madrid (Spain) went from March 31 to October 27 + $offset = Timezones::getRawOffset('Europe/Madrid', strtotime('March 31, 2019')); // $offset = 3600 + $offset = Timezones::getRawOffset('Europe/Madrid', strtotime('April 1, 2019')); // $offset = 7200 + $offset = Timezones::getGmtOffset('Europe/Madrid', strtotime('October 27, 2019')); // $offset = 'GMT+02:00' + $offset = Timezones::getGmtOffset('Europe/Madrid', strtotime('October 28, 2019')); // $offset = 'GMT+01:00' + +The string representation of the GMT offset can vary depending on the locale, so +you can pass the locale as the third optional argument:: + + $offset = Timezones::getGmtOffset('Europe/Madrid', strtotime('October 28, 2019'), 'ar')); // $offset = 'غرينتش+01:00' + $offset = Timezones::getGmtOffset('Europe/Madrid', strtotime('October 28, 2019'), 'dz')); // $offset = 'ཇི་ཨེམ་ཏི་+01:00' + +Finally, you can also check if a given timezone ID is valid:: $isValidTimezone = Timezones::exists($timezoneId); @@ -297,3 +342,5 @@ Learn more .. _ICU library: http://site.icu-project.org/ .. _`Unicode ISO 15924 Registry`: https://www.unicode.org/iso15924/iso15924-codes.html .. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 +.. _`UTC/GMT time offsets`: https://en.wikipedia.org/wiki/List_of_UTC_time_offsets +.. _`daylight saving time (DST)`: https://en.wikipedia.org/wiki/Daylight_saving_time From d28cfd3be18082bf0d2544cee495806b753b778f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 29 May 2019 15:22:26 +0200 Subject: [PATCH 172/499] Deprecate the LoggingMiddleware in Symfony 4.3 --- components/messenger.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/messenger.rst b/components/messenger.rst index 3825d1571ae..be06f27f3cf 100644 --- a/components/messenger.rst +++ b/components/messenger.rst @@ -79,6 +79,11 @@ are configured for you: #. :class:`Symfony\\Component\\Messenger\\Middleware\\SendMessageMiddleware` (enables asynchronous processing) #. :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 2f91fe2f32267e327ff8a14ce334a628cd0c7686 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 29 May 2019 15:36:05 +0200 Subject: [PATCH 173/499] Minor 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 d8034ffc6aa..ed2db8fb45b 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -720,8 +720,8 @@ 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 use default options. -Each scoped client also define a corresponding named autowiring alias. -E.g. if you use +Each scoped client also defines a corresponding named autowiring alias. +If you use for example ``Symfony\Constracts\HttpClient\HttpClientInterface $myApiClient`` as the type and name of an argument, autowiring will inject the ``my_api.client`` service into your autowired classes. From 755e2ffe26c91db952666d9cd82a47dfbc9e154a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 30 May 2019 12:50:42 +0200 Subject: [PATCH 174/499] [HttpClient] Fixed some missing references --- reference/configuration/framework.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index ed2db8fb45b..ed86f2d2ec5 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -90,7 +90,7 @@ Configuration * `http_client`_ - * `default_options`_ + * :ref:`default_options ` * `bindto`_ * `cafile`_ @@ -111,7 +111,7 @@ Configuration * `verify_peer`_ * `max_host_connections`_ - * `scoped_clients`_ + * :ref:`scoped_clients ` * `scope`_ * `auth_basic`_ @@ -687,6 +687,8 @@ When the HttpClient component is installed, an HTTP client is available as a service named ``http_client`` or using the autowiring alias :class:`Symfony\\Constracts\\HttpClient\\HttpClientInterface`. +.. _reference-http-client-default-options: + This service can be configured using ``framework.http_client.default_options``: .. code-block:: yaml @@ -700,6 +702,8 @@ This service can be configured using ``framework.http_client.default_options``: headers: [{ 'X-Powered-By': 'ACME App' }] max_redirects: 7 +.. _reference-http-client-scoped-clients: + Multiple pre-configured HTTP client services can be defined, each with its service name defined as a key under ``scoped_clients``. Scoped clients inherit the default options defined for the ``http_client`` service. You can override From bda585ea6cf9a2e40521fff2cd31b8413fac78d9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 30 May 2019 12:53:59 +0200 Subject: [PATCH 175/499] [HttpClient] Fixed some wrong class FQCN --- 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 ed2db8fb45b..ce0008002cd 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -685,7 +685,7 @@ http_client When the HttpClient component is installed, an HTTP client is available as a service named ``http_client`` or using the autowiring alias -:class:`Symfony\\Constracts\\HttpClient\\HttpClientInterface`. +:class:`Symfony\\Contracts\\HttpClient\\HttpClientInterface`. This service can be configured using ``framework.http_client.default_options``: @@ -722,7 +722,7 @@ use default options. Each scoped client also defines a corresponding named autowiring alias. If you use for example -``Symfony\Constracts\HttpClient\HttpClientInterface $myApiClient`` +``Symfony\Contracts\HttpClient\HttpClientInterface $myApiClient`` as the type and name of an argument, autowiring will inject the ``my_api.client`` service into your autowired classes. From 3e670803994c4bb86285aa8304cba73ff7f3f2a5 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sun, 26 May 2019 08:44:04 -0400 Subject: [PATCH 176/499] Updating messenger docs for 4.3 Co-Authored-By: Wouter J Co-Authored-By: Maxime Helias --- messenger.rst | 1373 +++++++++++++++++++++--------- messenger/custom-transport.rst | 138 +++ messenger/doctrine-transport.rst | 214 ----- messenger/multiple_buses.rst | 10 +- 4 files changed, 1114 insertions(+), 621 deletions(-) create mode 100644 messenger/custom-transport.rst delete mode 100644 messenger/doctrine-transport.rst diff --git a/messenger.rst b/messenger.rst index fb1ecec950c..91f3b4ac9ff 100644 --- a/messenger.rst +++ b/messenger.rst @@ -1,30 +1,34 @@ .. index:: single: Messenger -How to Use the Messenger -======================== +Messenger: Sync & Queued Message Handling +========================================= -Symfony's Messenger provides a message bus and some routing capabilities to send -messages within your application and through transports such as message queues. -Before using it, read the :doc:`Messenger component docs ` -to get familiar with its concepts. +Messenger provides a message bus with the ability to send messages and then +handle them immediately in your application or send them through transports +(e.g. queues) to be handled later. To learn more deeply about it, read the +:doc:`Messenger component docs ` docs. Installation ------------ In applications using :doc:`Symfony Flex `, run this command to -install messenger before using it: +install messenger: .. code-block:: terminal $ composer require messenger -Message -------- +Creating a Message & Handler +---------------------------- -Before you can send a message, you must create it first. There is no specific -requirement for a message, except it should be serializable and unserializable -by a Symfony Serializer instance:: +Messenger centers around two different classes that you'll create: (1) a message +class that holds data and (2) a handler(s) class that will be called when that +message is dispatched. The handler class will read the message class and perform +some task. + +There are no specific requirements for a message class, except that it can be +serialized:: // src/Message/SmsNotification.php namespace App\Message; @@ -38,35 +42,17 @@ by a Symfony Serializer instance:: $this->content = $content; } - // ...getters - } - -Using the Messenger Service ---------------------------- - -Once enabled, the ``message_bus`` service can be injected in any service where -you need it, like in a controller:: - - // src/Controller/DefaultController.php - namespace App\Controller; - - use App\Message\SmsNotification; - use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - use Symfony\Component\Messenger\MessageBusInterface; - - class DefaultController extends AbstractController - { - public function index(MessageBusInterface $bus) + public function getContent(): string { - $bus->dispatch(new SmsNotification('A string to be sent...')); + return $this->content; } } -Registering Handlers --------------------- +.. _messenger-handler: -In order to do something when your message is dispatched, you need to create a -message handler. It's a class with an ``__invoke`` method:: +A message handler is a PHP callable, the easiest way to create it is to create a class that implements +``MessageHandlerInterface`` and has an ``__invoke()`` method that's +type-hinted with the message class (or a message interface):: // src/MessageHandler/SmsNotificationHandler.php namespace App\MessageHandler; @@ -78,78 +64,76 @@ message handler. It's a class with an ``__invoke`` method:: { public function __invoke(SmsNotification $message) { - // do something with it. + // ... do some work - like sending an SMS message! } } -Message handlers must be registered as services and :doc:`tagged ` -with the ``messenger.message_handler`` tag. If you're using the -:ref:`default services.yaml configuration ` and implement -:class:`Symfony\\Component\\Messenger\\Handler\\MessageHandlerInterface` -or :class:`Symfony\\Component\\Messenger\\Handler\\MessageSubscriberInterface`, -this is already done for you, thanks to :ref:`autoconfiguration `. +Thanks to :ref:`autoconfiguration ` 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 +also :ref:`manually configure message handlers `. To +see all the configured handlers, run: -If you're not using service autoconfiguration, then you need to add this config: - -.. configuration-block:: +.. code-block:: terminal - .. code-block:: yaml + $ php bin/console debug:messenger - # config/services.yaml - services: - App\MessageHandler\SmsNotificationHandler: - tags: [messenger.message_handler] +Dispatching the Message +----------------------- - .. code-block:: xml +You're ready! To dispatch the message (and call the handler), inject the +``message_bus`` service (via the ``MessageBusInterface``), like in a controller:: - - - + // src/Controller/DefaultController.php + namespace App\Controller; - - - - - - + use App\Message\SmsNotification; + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Messenger\MessageBusInterface; - .. code-block:: php + class DefaultController extends AbstractController + { + public function index(MessageBusInterface $bus) + { + // will cause the SmsNotificationHandler to be called + $bus->dispatch(new SmsNotification('Look! I created a message!')); - // config/services.php - use App\MessageHandler\SmsNotificationHandler; + // or use the shortcut + $this->dispatchMessage(new SmsNotification('Look! I created a message!')); - $container->register(SmsNotificationHandler::class) - ->addTag('messenger.message_handler'); + // ... + } + } -.. note:: +Transports: Async/Queued Messages +--------------------------------- - If the message cannot be guessed from the handler's type-hint, use the - ``handles`` attribute on the tag. +By default, messages are handled as soon as they are dispatched. If you want +to handle a message asynchronously, you can configure a transport. A transport +is capable of sending messages (e.g. to a queueing system) and then +:ref:`receiving them via a worker`. Messenger supports +:ref:`multiple transports `. -Transports ----------- +.. note:: -By default, messages are processed as soon as they are dispatched. If you prefer -to process messages asynchronously, you must configure a transport. These -transports communicate with your application via queuing systems or third parties. + If you want to use a transport that's not supported, check out the + `Enqueue's transport`_, which supports things like Kafka, Amazon SQS and + Google Pub/Sub. -There are the following built-in transports: +A transport is registered using a "DSN". Thanks to Messenger's Flex recipe, your +``.env`` file already has a few examples. -- `AMQP`_ -- Doctrine -- `Redis`_ +.. code-block:: bash -.. note:: + # MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages + # MESSENGER_TRANSPORT_DSN=doctrine://default + # MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages - If you need more message brokers, you should have a look at `Enqueue's transport`_ - which supports things like Kafka, Amazon SQS or Google Pub/Sub. +Uncomment whichever transport you want (or set it in ``.env.local``). See +:ref:`messenger-transports-config` for more details. -A transport is registered using a "DSN", which is a string that represents the -connection credentials and configuration. By default, when you've installed -the messenger component, the following configuration should have been created: +Next, in ``config/packages/messenger.yaml``, let's define a transport called ``async`` +that uses this configuration: .. configuration-block:: @@ -159,7 +143,12 @@ the messenger component, the following configuration should have been created: framework: messenger: transports: - your_transport: "%env(MESSENGER_TRANSPORT_DSN)%" + async: "%env(MESSENGER_TRANSPORT_DSN)%" + + # or expanded to configure more options + #async: + # dsn: "%env(MESSENGER_TRANSPORT_DSN)%" + # options: [] .. code-block:: xml @@ -175,7 +164,14 @@ the messenger component, the following configuration should have been created: - + %env(MESSENGER_TRANSPORT_DSN)% + + + + + @@ -186,74 +182,24 @@ the messenger component, the following configuration should have been created: $container->loadFromExtension('framework', [ 'messenger' => [ 'transports' => [ - 'your_transport' => '%env(MESSENGER_TRANSPORT_DSN)%', + 'async' => '%env(MESSENGER_TRANSPORT_DSN)%', + + // or expanded to configure more options + 'async' => [ + 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', + 'options' => [] + ], ], ], ]); -This will also configure the following services for you: - -#. A ``messenger.sender.your_transport`` sender to be used when routing messages; -#. A ``messenger.receiver.your_transport`` receiver to be used when consuming messages. - -Now define the ``MESSENGER_TRANSPORT_DSN`` in the ``.env`` file. -See examples beneath how to configure the DSN for different transports. +.. _messenger-routing: -AMQP -~~~~ +Routing Messages to a Transport +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: bash - - # .env - MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages - -This is enough to allow you to route your message to the ``amqp`` transport. - -.. note:: - - In order to use Symfony's built-in AMQP transport, you will need the AMQP - PHP extension and the Serializer component. Ensure that they are installed with: - - .. code-block:: terminal - - $ composer require symfony/amqp-pack - -Redis -~~~~~ - -.. versionadded:: 4.3 - - The Redis transport was introduced in Symfony 4.3. - -The Redis transport will use `streams`_ to queue messages. - -.. code-block:: bash - - # .env - MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages - -This is enough to allow you to route your message to the Redis transport. - -If you have multiple systems to receive the same messages you could use different groups -to achieve this: - -.. code-block:: bash - - # .env - MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages/group1/consumer1 - -.. note:: - - In order to use Symfony's built-in Redis transport, you will need the Redis - PHP extension (^4.2), a running Redis server (^5.0) and the Serializer component. - -Routing -------- - -Instead of calling a handler, you have the option to route your message(s) to a -sender. Part of a transport, it is responsible for sending your message somewhere. -You can configure which message is routed to which sender with the following -configuration: +Now that you have a transport configured, instead of handling a message immediately, +you can configure them to be sent to a transport: .. configuration-block:: @@ -262,8 +208,12 @@ configuration: # config/packages/messenger.yaml framework: messenger: + transports: + async: "%env(MESSENGER_TRANSPORT_DSN)%" + routing: - 'My\Message\Message': your_transport # The name of the defined transport + # async is whatever name you gave your transport above + 'App\Message\SmsNotification': async .. code-block:: xml @@ -279,8 +229,9 @@ configuration: - - + + + @@ -292,16 +243,18 @@ configuration: $container->loadFromExtension('framework', [ 'messenger' => [ 'routing' => [ - 'My\Message\Message' => 'your_transport', + // async is whatever name you gave your transport above + 'App\Message\SmsNotification' => 'async', ], ], ]); -Such configuration would only route the ``My\Message\Message`` message to be -asynchronous, the rest of the messages would still be directly handled. +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 +matched under ``routing`` will still be handled immediately. -You can route all classes of messages to the same sender using an asterisk -instead of a class name: +You can also route classes by their parent class or interface. Or send messages +to multiple transport: .. configuration-block:: @@ -311,8 +264,11 @@ instead of a class name: framework: messenger: routing: - 'My\Message\MessageAboutDoingOperationalWork': another_transport - '*': your_transport + # route all messages that extend this example base class or interface + 'App\Message\AbstractAsyncMessage': async + 'App\Message\AsyncMessageInterface': async + + 'My\Message\ToBeSentToTwoSenders': [async, audit] .. code-block:: xml @@ -328,11 +284,16 @@ instead of a class name: - - + + + + + + - - + + + @@ -344,13 +305,72 @@ instead of a class name: $container->loadFromExtension('framework', [ 'messenger' => [ 'routing' => [ - 'My\Message\Message' => 'another_transport', - '*' => 'your_transport', + // route all messages that extend this example base class or interface + 'App\Message\AbstractAsyncMessage' => 'async', + 'App\Message\AsyncMessageInterface' => 'async', + 'My\Message\ToBeSentToTwoSenders' => ['async', 'audit'], ], ], ]); -A class of messages can also be routed to multiple senders by specifying a list: +Doctrine Entities in Messages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to pass a Doctrine entity in a message, it's better to pass the entity's +primary key (or whatever relevant information the handler actually needs, like ``email``, +etc) instead of the object:: + + class NewUserWelcomeEmail + { + private $userId; + + public function __construct(int $userId) + { + $this->userId = $userId; + } + + public function getUserId(): int + { + return $this->userId; + } + } + +Then, in your handler, you can query for a fresh object:: + + // src/MessageHandler/NewUserWelcomeEmailHandler.php + namespace App\MessageHandler; + + use App\Message\NewUserWelcomeEmail; + use App\Repository\UserRepository; + use Symfony\Component\Messenger\Handler\MessageHandlerInterface; + + class NewUserWelcomeEmailHandler implements MessageHandlerInterface + { + private $userRepository; + + public function __construct(UserRepository $userRepository) + { + $this->userRepository = $userRepository; + } + + public function __invoke(NewUserWelcomeEmail $welcomeEmail) + { + $user = $this->userRepository->find($welcomeEmail->getUserId()); + + // ... send an email! + } + } + +This guarantees the entity contains fresh data. + +Handling Messages Synchronously +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a message doesn't :ref:`match any routing rules `, it won't +be sent to any transport and will be handled immediately. In some cases (like +when :ref:`sending handlers to different transports`), +it's easier or more flexible to handle this explicitly: by creating a ``sync`` +transport and "sending" messages there to be handled immediately: .. configuration-block:: @@ -359,8 +379,13 @@ A class of messages can also be routed to multiple senders by specifying a list: # config/packages/messenger.yaml framework: messenger: + transports: + # ... other transports + + sync: 'sync://' + routing: - 'My\Message\ToBeSentToTwoSenders': [your_transport, audit] + App\Message\SmsNotification: sync .. code-block:: xml @@ -376,9 +401,12 @@ A class of messages can also be routed to multiple senders by specifying a list: - - - + + + + + + @@ -389,14 +417,77 @@ A class of messages can also be routed to multiple senders by specifying a list: // config/packages/messenger.php $container->loadFromExtension('framework', [ 'messenger' => [ + 'transports' => [ + // ... other transports + + 'sync' => 'sync://', + ], 'routing' => [ - 'My\Message\ToBeSentToTwoSenders' => ['your_transport', 'audit'], + 'App\Message\SmsNotification' => 'sync', ], ], ]); -By specifying the ``send_and_handle`` option, you can also route a class of messages to a sender -while still having them passed to their respective handler: +Creating your Own Transport +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also create your own transport if you need to send or receive messages +from something that is not supported. See :doc:`/messenger/custom-transport`. + +.. _messenger-worker: + +Consuming Messages (Running the Worker) +--------------------------------------- + +Once your messages have been routed, in most cases, you'll need to "consume" them. +You can do this with the ``messenger:consume`` command: + +.. code-block:: terminal + + $ php bin/console messenger:consume async + + # use -vv to see details about what's happening + $ php bin/console messenger:consume async -vv + +.. versionadded:: 4.3 + + The ``messenger:consume`` command was renamed in Symfony 4.3 (previously it + was called ``messenger:consume-messages``). + +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". + +Deploying to Production +~~~~~~~~~~~~~~~~~~~~~~~ + +On production, there are a few important things to think about: + +**Use Supervisor to keep your worker(s) running** + You'll want one or more "workers" running at all times. To do that, use a + process control system like :ref:`Supervisor `. + +**Don't Let Workers Run Forever** + Some services (like Doctrine's EntityManager) will consume more memory + over time. So, instead of allowing your worker to run forever, use a flag + like ``messenger:consume --limit=10`` to tell your worker to only handle 10 + messages before exiting (then Supervisor will create a new process). There + are also other options like ``--memory-limit=128M`` and ``--time-limit=3600``. + +**Restart Workers on Deploy** + Each time you deploy, you'll need to restart all your worker processes so + that they see the newly deployed code. To do this, run ``messenger:stop-workers`` + on deploy. This will signal to each worker that it should finish the message + it's currently handling and shut down gracefully. Then, Supervisor will create + new worker processes. The command uses the :ref:`app ` + cache internally - so make sure this is configured to use an adapter you like. + +Prioritized Transports +~~~~~~~~~~~~~~~~~~~~~~ + +Sometimes certain types of messages should have a higher priority and be handled +before others. To make this possible, you can create multiple transports and route +different messages to them. For example: .. configuration-block:: @@ -405,10 +496,21 @@ while still having them passed to their respective handler: # config/packages/messenger.yaml framework: messenger: + transports: + async_priority_high: + dsn: '%env(MESSENGER_TRANSPORT_DSN)%' + options: + # queue_name is specific to the doctrine transport + # try "exchange" for amqp or "group1" for redis + queue_name: high + async_priority_low: + dsn: '%env(MESSENGER_TRANSPORT_DSN)%' + options: + queue_name: low + routing: - 'My\Message\ThatIsGoingToBeSentAndHandledLocally': - senders: [your_transport] - send_and_handle: true + 'App\Message\SmsNotification': async_priority_low + 'App\Message\NewUserWelcomeEmail': async_priority_high .. code-block:: xml @@ -424,8 +526,18 @@ while still having them passed to their respective handler: - - + + + + + + + + + + + + @@ -436,63 +548,239 @@ while still having them passed to their respective handler: // config/packages/messenger.php $container->loadFromExtension('framework', [ 'messenger' => [ - 'routing' => [ - 'My\Message\ThatIsGoingToBeSentAndHandledLocally' => [ - 'senders' => ['your_transport'], - 'send_and_handle' => true, + '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', ], ], ]); -Consuming Messages +You can then run individual workers for each transport or instruct one worker +to handle messages in a priority order: + +.. code-block:: terminal + + $ php bin/console messenger:consume async_priority_high async_priority_low + +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-supervisor: + +Supervisor Configuration +~~~~~~~~~~~~~~~~~~~~~~~~ + +Supervisor is a great tool to guarantee that your worker process(es) is +*always* running (even if it closes due to failure, hitting a message limit +or thanks to ``messenger:stop-workers``). You can install it on Ubuntu, for +example, via: + +.. code-block:: terminal + + $ sudo apt-get install supervisor + +Supervisor configuration files typically live in a ``/etc/supervisor/conf.d`` +directory. For example, you can create a new ``messenger-worker.conf`` file +there to make sure that 2 instances of ``messenger:consume`` are running at all +times: + +.. code-block:: ini + + ;/etc/supervisor/conf.d/messenger-worker.conf + [program:messenger-consume] + command=php /path/to/your/app/bin/console messenger:consume async --time-limit=3600 + user=ubuntu + numprocs=2 + autostart=true + autorestart=true + 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: + +.. code-block:: terminal + + $ sudo supervisorctl reread + + $ sudo supervisorctl update + + $ sudo supervisorctl start messenger-consume + +See the `Supervisor docs`_ for more details. + +Retries & Failures ------------------ -Once your messages have been routed, you will like to consume your messages in -most of the cases. To do so, use the ``messenger:consume`` command like this: +If an exception is thrown while consuming a message from a transport it will +automatically be re-sent to the transport to be tried again. By default, a message +will be retried 3 times before being discarded or +:ref:`sent to the failure transport `. Each retry +will also be delayed, in case the failure was due to a temporary issue. All of +this is configurable for each transport: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + 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 + +Avoiding Retrying +~~~~~~~~~~~~~~~~~ + +Sometimes handling a message might fail in a way that you *know* is permanent +and should not be retried. If you throw +:class:`Symfony\\Component\\Messenger\\Exception\\UnrecoverableMessageHandlingException`, +the message will not be retried. + +.. _messenger-failure-transport: + +Saving & Retrying Failed Messages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a message fails it is retried multiple times (``max_retries``) and then will +be discarded. To avoid this happening, you can instead configure a ``failure_transport``: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + # after retrying, messages will be sent to the "failed" transport + failure_transport: failed + + transports: + # ... other transports + + failed: '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 +``messenger:consume failed`` to consume this like a normal transport, you'll +usually want to manually view the messages in the failure transport and choose +to retry them: .. code-block:: terminal - $ php bin/console messenger:consume your_transport + # see all messages in the failure transport + $ php bin/console messenger:failed:show -The first argument is the receiver's service name. It might have been created by -your ``transports`` configuration or it can be your own receiver. -It also requires a ``--bus`` option in case you have multiple buses configured, -which is the name of the bus to which received messages should be dispatched. + # see details about a specific failure + $ php bin/console messenger:failed:show 20 -vv -.. versionadded:: 4.3 + # view and retry messages one-by-one + $ php bin/console messenger:failed:retry -vv - The ``messenger:consume`` command was renamed in Symfony 4.3 (previously it - was called ``messenger:consume-messages``). + # retry specific messages + $ php bin/console messenger:failed:retry 20 30 --force -Middleware ----------- + # remove a message without retrying it + $ php bin/console messenger:failed:retry 20 -What happens when you dispatch a message to a message bus(es) depends on its -collection of middleware (and their order). By default, the middleware configured -for each bus looks like this: +.. _messenger-transports-config: -#. ``logging`` middleware. Responsible for logging the beginning and the end of the - message within the bus; +Transport Configuration +----------------------- -#. Your own collection of middleware_; +Messenger supports a number of different transport types, each with their own +options. + +AMQP Transport +~~~~~~~~~~~~~~ + +The ``amqp`` transport configuration looks like this: -#. ``send_message`` middleware. Will route the messages you configured to their - corresponding sender and stop the middleware chain; +.. code-block:: bash + + # .env + MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages -#. ``handle_message`` middleware. Will call the message handler(s) for the - given message. +To use Symfony's built-in AMQP transport, you need the AMQP PHP extension. .. note:: - These middleware names are actually shortcuts working by convention. - The real service ids are prefixed with the ``messenger.middleware.`` namespace. + 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). -Disabling default Middleware -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +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\\AmqpExt\\Connection`. + +You can also configure AMQP-specific settings on your message by adding +:class:`Symfony\\Component\\Messenger\\Transport\\AmqpExt\\AmqpStamp` to +your Envelope:: + + use Symfony\Component\Messenger\Transport\AmqpExt\AmqpStamp; + // ... + + $attributes = []; + $bus->dispatch(new SmsNotification(), [ + new AmqpStamp('custom-routing-key', AMQP_NOPARAM, $attributes) + ]); + +Doctrine Transport +~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 4.3 + + The Doctrine transport was introduced in Symfony 4.3. + +The Doctrine transport can be used to store messages in a database table. + +.. code-block:: bash -If you don't want the default collection of middleware to be present on your bus, -you can disable them like this: + # .env + MESSENGER_TRANSPORT_DSN=doctrine://default + +The format is ``doctrine://``, in case you have multiple connections +and want to use one other than the "default". The transport will automatically create +a table named ``messenger_messages`` (this is configurable) when the transport is +first used. You can disable that with the ``auto_setup`` option and set the table +up manually by calling the ``messenger:setup-transports`` command. + +.. caution:: + + If you use Doctrine Migrations, each generated migration will try to drop + the ``messenger_messages`` table and needs to be removed manually. You + cannot (yet) use ``doctrine.dbal.schema_filter`` to avoid. See + https://github.com/symfony/symfony/issues/31623. + +The transport has a number of options: .. configuration-block:: @@ -501,9 +789,12 @@ you can disable them like this: # config/packages/messenger.yaml framework: messenger: - buses: - messenger.bus.default: - default_middleware: false + 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 @@ -519,7 +810,10 @@ you can disable them like this: - + + + + @@ -529,84 +823,308 @@ you can disable them like this: // config/packages/messenger.php $container->loadFromExtension('framework', [ 'messenger' => [ - 'buses' => [ - 'messenger.bus.default' => [ - 'default_middleware' => false, + 'transports' => [ + 'async_priority_high' => 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%?queue_name=high_priority', + 'async_priority_low' => [ + 'dsn' => '%env(MESSENGER_TRANSPORT_DSN)%', + 'options' => [ + 'queue_name' => 'normal_priority' + ] ], ], ], ]); -Adding your own Middleware -~~~~~~~~~~~~~~~~~~~~~~~~~~ +Options defined under ``options`` take precedence over ones defined in the DSN. + +================== =================================== ======= + Option Description Default +================== =================================== ======= +table_name Name of the table messenger_messages +queue_name Name of the queue (a column in the default + table, to use-use one table for + multiple transports) +redeliver_timeout Timeout before retrying a messages 3600 + that's in the queue but in the + "handling" state (if a worker died + for some reason, this will occur, + eventually you should retry the + message) +auto_setup Whether the table should be created + automatically during send / get. true +================== =================================== ======= + +Redis Transport +~~~~~~~~~~~~~~~ -As described in the component documentation, you can add your own middleware -within the buses to add some extra capabilities like this: +.. versionadded:: 4.3 -.. configuration-block:: + The Redis transport was introduced in Symfony 4.3. + +The Redis transport uses `streams`_ to queue messages. + +.. code-block:: bash + + # .env + MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages + +To use the Redis transport, you will need the Redis PHP extension (^4.2) and +a running Redis server (^5.0). + +.. caution:: + + The Redis transport does not support "delayed" messages. + +A number of options can be configured via the DSN of 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 +serializer How to serialize the final payload ``Redis::SERIALIZER_PHP`` + in Redis (the + ``Redis::OPT_SERIALIZER`` option) +================== =================================== ======= + +In Memory Transport +~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 4.3 + + The ``in-memory`` transport was introduced in Symfony 4.3. + +The ``in-memory`` transport does not actually delivery messages. Instead, it +holds them in memory during the request, which can be useful for testing. +For example, if you have an ``async_priority_normal`` transport, you could +override it in the ``test`` environment to use this transport: + +.. code-block:: yaml + + # config/packages/test/messenger.yaml + framework: + messenger: + transports: + async_priority_normal: '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 +during a request:: + + // tests/DefaultControllerTest.php + namespace App\Tests; + + use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + use Symfony\Component\Messenger\Transport\InMemoryTransport; + + class DefaultControllerTest extends WebTestCase + { + public function testSomething() + { + $client = static::createClient(); + // ... + + $this->assertSame(200, $client->getResponse()->getStatusCode()); + + /* @var InMemoryTransport $transport */ + $transport = self::$container->get('messenger.transport.async_priority_normal'); + $this->assertCount(1, $transport->get()); + } + } + +Serializing Messages +~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 4.3 + The default serializer changed in 4.3 from the Symfony serializer to the + native PHP serializer. Existing applications should configure their transports + to use the Symfony serializer to avoid losing already-queued messages after + upgrading. + +When messages are sent to (and received from) a transport, they're serialized +using PHP's native ``serialize()`` & ``unserialize()`` functions. You can change +this globally (or for each transport) to a service that implements +:class:`Symfony\\Component\\Messenger\\Transport\\Serialization\\SerializerInterface`: + +.. configuration-block:: .. code-block:: yaml # config/packages/messenger.yaml framework: messenger: - buses: - messenger.bus.default: - middleware: - - 'App\Middleware\MyMiddleware' - - 'App\Middleware\AnotherMiddleware' + serializer: + default_serializer: messenger.transport.symfony_serializer + symfony_serializer: + format: json + context: { } + + transports: + 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. +If you *do* choose to use the Symfony serializer, you can control the context +on a case-by-case basis via the :class:`Symfony\\Component\\Messenger\\Stamp\\SerializerStamp` +(see `Envelopes & Stamps`_). + +Customizing Handlers +-------------------- + +.. _messenger-handler-config: + +Manually Configuring Handlers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Symfony will normally :ref:`find and register your handler automatically `. +But, you can also configure a handler manually - and pass it some extra config - +by tagging the handler service with ``messenger.message_handler`` + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + App\MessageHandler\SmsNotificationHandler: + tags: [messenger.message_handler] + + # or configure with options + tags: + - + name: messenger.message_handler + # only needed if can't be guessed by type-hint + handles: App\Message\SmsNotification + + # options returned by getHandledMessages() are supported here .. code-block:: xml - + + https://symfony.com/schema/dic/services/services-1.0.xsd"> - - - - - - - - + + + + + .. code-block:: php - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'buses' => [ - 'messenger.bus.default' => [ - 'middleware' => [ - 'App\Middleware\MyMiddleware', - 'App\Middleware\AnotherMiddleware', - ], - ], - ], - ], - ]); + // config/services.php + use App\MessageHandler\SmsNotificationHandler; -Note that if the service is abstract, a different instance of the service will -be created per bus. + $container->register(SmsNotificationHandler::class) + ->addTag('messenger.message_handler'); -Using Middleware Factories -~~~~~~~~~~~~~~~~~~~~~~~~~~ +Handler Subscriber & Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A handler class can handle multiple messages or configure itself by implementing +:class:`Symfony\\Component\\Messenger\\Handler\\MessageSubscriberInterface`:: + + // src/MessageHandler/SmsNotificationHandler.php + namespace App\MessageHandler; -Some third-party bundles and libraries provide configurable middleware via -factories. + use App\Message\OtherSmsNotification; + use App\Message\SmsNotification; + use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; -For instance, the ``messenger.middleware.doctrine_transaction`` is a -built-in middleware wired automatically when the DoctrineBundle and the Messenger -component are installed and enabled. -This middleware can be configured to define the entity manager to use: + class SmsNotificationHandler implements MessageSubscriberInterface + { + public function __invoke(SmsNotification $message) + { + // ... + } + + public function handleOtherSmsNotification(OtherSmsNotification $message) + { + // ... + } + + public static function getHandledMessages(): iterable + { + // handle this message on __invoke + yield SmsNotification::class; + + // also handle this message on handleOtherSmsNotification + yield OtherSmsNotification::class => [ + 'method' => 'handleOtherSmsNotification', + //'priority' => 0, + //'bus' => 'messenger.bus.default', + ]; + } + } + +.. _messenger-handlers-different-transports: + +Sending Handlers to Different Transports +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each message can have multiple handlers, and when a message is consumed +*all* of its handlers are called. But you can also configure a handler to only +be called when it's received from a *specific* transport. This allows you to +have a single message where each handler is called by a different "worker" +that's consuming a different transport. + +Suppose you have an ``UploadedImage`` message with two handlers: + +* ``ThumbnailUploadedImageHandler``: you want this to be handled by + a transport called ``image_transport`` + +* ``NotifyAboutNewUploadedImageHandler``: you want this to be handled + by a transport called ``async_priority_normal`` + +To do this, add the ``from_transport`` option to each handler. For example:: + + // src/MessageHandler/ThumbnailUploadedImageHandler.php + namespace App\MessageHandler; + + use App\Message\UploadedImage; + use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; + + class ThumbnailUploadedImageHandler implements MessageSubscriberInterface + { + public function __invoke(UploadedImage $uploadedImage) + { + // do some thumbnailing + } + + public static function getHandledMessages(): iterable + { + yield UploadedImage::class => [ + 'from_transport' => 'image_transport', + ]; + } + } + +And similarly:: + + // src/MessageHandler/NotifyAboutNewUploadedImageHandler.php + // ... + + class NotifyAboutNewUploadedImageHandler implements MessageSubscriberInterface + { + // ... + + public static function getHandledMessages(): iterable + { + yield UploadedImage::class => [ + 'from_transport' => 'async_priority_normal', + ]; + } + } + +Then, make sure to "route" your message to *both* transports: .. configuration-block:: @@ -615,13 +1133,13 @@ This middleware can be configured to define the entity manager to use: # config/packages/messenger.yaml framework: messenger: - buses: - command_bus: - middleware: - # Using the default configured entity manager name - - doctrine_transaction - # Using another entity manager - - doctrine_transaction: ['custom'] + transports: + async_priority_normal: # ... + image_transport: # ... + + routing: + # ... + 'App\Message\UploadedImage': [image_transport, async_priority_normal] .. code-block:: xml @@ -637,14 +1155,13 @@ This middleware can be configured to define the entity manager to use: - - - - - - custom - - + + + + + + + @@ -654,168 +1171,161 @@ This middleware can be configured to define the entity manager to use: // config/packages/messenger.php $container->loadFromExtension('framework', [ 'messenger' => [ - 'buses' => [ - 'command_bus' => [ - 'middleware' => [ - // Using the default configured entity manager name - 'doctrine_transaction', - // Using another entity manager - ['id' => 'doctrine_transaction', 'arguments' => ['custom']], - ], - ], + 'transports' => [ + 'async_priority_normal' => '...', + 'image_transport' => '...', ], + 'routing' => [ + 'App\Message\UploadedImage' => ['image_transport', 'async_priority_normal'] + ] ], ]); -Defining such configurable middleware is based on Symfony's -:doc:`dependency injection ` features: +That's it! You can now consume each transport: -.. configuration-block:: +.. code-block:: terminal - .. code-block:: yaml + # will only call ThumbnailUploadedImageHandler when handling the message + $ php bin/console messenger:consume image_transport -vv - # config/services.yaml - services: - messenger.middleware.doctrine_transaction: - class: Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddleware - # Definition is abstract, so a child definition will be created, per bus - abstract: true - # Main dependencies are defined by the parent definitions. - # Arguments provided in the middleware config will be appended on the child definition. - arguments: ['@doctrine'] + $ php bin/console messenger:consume async_priority_normal -vv - .. code-block:: xml +.. caution:: - - - + If a handler does *not* have ``from_transport`` config, it will be executed + on *every* transport that the message is received from. - - - abstract="true"> - - - - - - +Extending Messenger +------------------- - .. code-block:: php +Envelopes & Stamps +~~~~~~~~~~~~~~~~~~ - // config/services.php - use Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddleware; - use Symfony\Component\DependencyInjection\Reference; +A message can be any PHP object. Sometimes, you may need to configure something +extra about the message - like the way it should be handled inside Amqp or adding +a delay before the message should be handled. You can do that by adding a "stamp" +to your message:: - $container->register('messenger.middleware.doctrine_transaction', DoctrineTransactionMiddleware::class) - // Definition is abstract, so a child definition will be created, per bus - ->setAbstract(true) - // Main dependencies are defined by the parent definitions. - // Arguments provided in the middleware config will be appended on the child definition. - ->setArguments([new Reference('doctrine')]); + use Symfony\Component\Messenger\Envelope; + use Symfony\Component\Messenger\MessageBusInterface; + use Symfony\Component\Messenger\Stamp\DelayStamp; -.. note:: + public function index(MessageBusInterface $bus) + { + $bus->dispatch(new SmsNotification('...'), [ + // wait 5 seconds before processing + new DelayStamp(5000) + ]); - Middleware factories only allow appending scalar and array arguments in config - (no references to other services). For most advanced use-cases, register a - concrete definition of the middleware manually and use its id. + // or explicitly create an Envelope + $bus->dispatch(new Envelope(new SmsNotification('...'), [ + new DelayStamp(5000) + ])); -Your own Transport ------------------- + // ... + } -Once you have written your transport's sender and receiver, you can register your -transport factory to be able to use it via a DSN in the Symfony application. +Internally, each message is wrapped in an ``Envelope``, which holds the message +and stamps. You can create this manually or allow the message bus to do it. There +are a variety of different stamps for different purposes and they're used internally +to track information about a message - like the message bus that's handling it +or if it's being retried after failure. -Create your Transport Factory -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Middleware +~~~~~~~~~~ -You need to give FrameworkBundle the opportunity to create your transport from a -DSN. You will need a transport factory:: +What happens when you dispatch a message to a message bus depends on its +collection of middleware (and their order). By default, the middleware configured +for each bus looks like this: - use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; - use Symfony\Component\Messenger\Transport\Sender\SenderInterface; - use Symfony\Component\Messenger\Transport\TransportFactoryInterface; - use Symfony\Component\Messenger\Transport\TransportInterface; +#. ``add_bus_name_stamp_middleware`` - adds a stamp to record which bus this + message was dispatched into. - class YourTransportFactory implements TransportFactoryInterface - { - public function createTransport(string $dsn, array $options): TransportInterface - { - return new YourTransport(/* ... */); - } +#. ``dispatch_after_current_bus``- see :doc:`/messenger/message-recorder`. - public function supports(string $dsn, array $options): bool - { - return 0 === strpos($dsn, 'my-transport://'); - } - } +#. ``failed_message_processing_middleware`` - sends failed messages to the + :ref:`failure transport `. -The transport object needs to implement the ``TransportInterface`` (which simply combines -the ``SenderInterface`` and ``ReceiverInterface``). It will look like this:: +#. Your own collection of middleware_; - class YourTransport implements TransportInterface - { - public function send(Envelope $envelope): Envelope - { - // ... - } +#. ``send_message`` - if routing is configured for the transport, this sends + messages to that transport and stops the middleware chain. - public function receive(callable $handler): void - { - // ... - } +#. ``handle_message`` - calls the message handler(s) for the given message. - public function stop(): void - { - // ... - } - } +.. note:: -Register your Factory -~~~~~~~~~~~~~~~~~~~~~ + These middleware names are actually shortcuts names. The real service ids + are prefixed with ``messenger.middleware.``. + +You can add your own middleware to this list, or completely disable the default +middleware and *only* include your own: .. configuration-block:: .. code-block:: yaml - # config/services.yaml - services: - Your\Transport\YourTransportFactory: - tags: [messenger.transport_factory] + # config/packages/messenger.yaml + framework: + messenger: + buses: + messenger.bus.default: + middleware: + # service ids that implement Symfony\Component\Messenger\Middleware + - 'App\Middleware\MyMiddleware' + - 'App\Middleware\AnotherMiddleware' + + #default_middleware: false .. code-block:: xml - + + 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"> - - - - - + + + + + + + .. code-block:: php - // config/services.php - use Your\Transport\YourTransportFactory; + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'buses' => [ + 'messenger.bus.default' => [ + 'middleware' => [ + 'App\Middleware\MyMiddleware', + 'App\Middleware\AnotherMiddleware', + ], + 'default_middleware' => false, + ], + ], + ], + ]); - $container->register(YourTransportFactory::class) - ->setTags(['messenger.transport_factory']); -Use your Transport -~~~~~~~~~~~~~~~~~~ +.. note:: + + If a middleware service is abstract, a different instance of the service will + be created per bus. -Within the ``framework.messenger.transports.*`` configuration, create your -named transport using your own DSN: +Middleware for Doctrine +~~~~~~~~~~~~~~~~~~~~~~~ + +If you use Doctrine in your app, a number of optional middleware exist that you +may want to use: .. configuration-block:: @@ -824,8 +1334,27 @@ named transport using your own DSN: # config/packages/messenger.yaml framework: messenger: - transports: - yours: 'my-transport://...' + buses: + command_bus: + middleware: + # wraps all handlers in a single Doctrine transaction + # handlers do not need to call flush() and an error + # in any handler will cause a rollback + - doctrine_transaction + + # each time a message is handled, the Doctrine connection + # is "pinged" and reconnected if it's closed. Useful + # if your workers run for a long time and the database + # connection is sometimes lost + - doctrine_ping_connection + + # After handling, the Doctrine connection is closed, + # which can free up database connections in a worker, + # instead of keeping them open forever + - doctrine_close_connection + + # or pass a different entity manager to any + #- doctrine_transaction: ['custom'] .. code-block:: xml @@ -841,7 +1370,18 @@ named transport using your own DSN: - + + + + + + + + @@ -851,17 +1391,39 @@ named transport using your own DSN: // config/packages/messenger.php $container->loadFromExtension('framework', [ 'messenger' => [ - 'transports' => [ - 'yours' => 'my-transport://...', + 'buses' => [ + 'command_bus' => [ + 'middleware' => [ + 'doctrine_transaction', + 'doctrine_ping_connection', + 'doctrine_close_connection', + // Using another entity manager + ['id' => 'doctrine_transaction', 'arguments' => ['custom']], + ], + ], ], ], ]); -In addition of being able to route your messages to the ``yours`` sender, this -will give you access to the following services: +Messenger Events +~~~~~~~~~~~~~~~~ + +In addition to middleware, Messenger also dispatches several events. You can +:doc:`create an event listener ` to hook into various parts +of the process. For each, the event class is the event name: + +* :class:`Symfony\\Component\\Messenger\\Event\\SendMessageToTransportsEvent` +* :class:`Symfony\\Component\\Messenger\\Event\\WorkerMessageFailedEvent` +* :class:`Symfony\\Component\\Messenger\\Event\\WorkerMessageHandledEvent` +* :class:`Symfony\\Component\\Messenger\\Event\\WorkerMessageReceivedEvent` +* :class:`Symfony\\Component\\Messenger\\Event\\WorkerStoppedEvent` + +Multiple Buses, Command & Event Buses +------------------------------------- -#. ``messenger.sender.yours``: the sender; -#. ``messenger.receiver.yours``: the receiver. +Messenger gives you a single message bus service by default. But, you can configure +as many as you want, creating "command", "query" or "event" buses and controlling +their middleware. See :doc:`/messenger/multiple_buses`. Learn more ---------- @@ -874,3 +1436,4 @@ Learn more .. _`enqueue's transport`: https://github.com/php-enqueue/messenger-adapter .. _`streams`: https://redis.io/topics/streams-intro +.. _`Supervisor docs`: http://supervisord.org/ diff --git a/messenger/custom-transport.rst b/messenger/custom-transport.rst new file mode 100644 index 00000000000..4eac12ae4b6 --- /dev/null +++ b/messenger/custom-transport.rst @@ -0,0 +1,138 @@ +How to Create Your own Messenger Transport +========================================== + +Once you have written your transport's sender and receiver, you can register your +transport factory to be able to use it via a DSN in the Symfony application. + +Create your Transport Factory +----------------------------- + +You need to give FrameworkBundle the opportunity to create your transport from a +DSN. You will need a transport factory:: + + use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; + use Symfony\Component\Messenger\Transport\Sender\SenderInterface; + use Symfony\Component\Messenger\Transport\TransportFactoryInterface; + use Symfony\Component\Messenger\Transport\TransportInterface; + + class YourTransportFactory implements TransportFactoryInterface + { + public function createTransport(string $dsn, array $options): TransportInterface + { + return new YourTransport(/* ... */); + } + + public function supports(string $dsn, array $options): bool + { + return 0 === strpos($dsn, 'my-transport://'); + } + } + +The transport object needs to implement the ``TransportInterface`` (which simply combines +the ``SenderInterface`` and ``ReceiverInterface``). It will look like this:: + + class YourTransport implements TransportInterface + { + public function send(Envelope $envelope): Envelope + { + // ... + } + + public function receive(callable $handler): void + { + // ... + } + + public function stop(): void + { + // ... + } + } + +Register your Factory +--------------------- + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + Your\Transport\YourTransportFactory: + tags: [messenger.transport_factory] + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/services.php + use Your\Transport\YourTransportFactory; + + $container->register(YourTransportFactory::class) + ->setTags(['messenger.transport_factory']); + +Use your Transport +------------------ + +Within the ``framework.messenger.transports.*`` configuration, create your +named transport using your own DSN: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + transports: + yours: 'my-transport://...' + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'transports' => [ + 'yours' => 'my-transport://...', + ], + ], + ]); + +In addition of being able to route your messages to the ``yours`` sender, this +will give you access to the following services: + +#. ``messenger.sender.yours``: the sender; +#. ``messenger.receiver.yours``: the receiver. diff --git a/messenger/doctrine-transport.rst b/messenger/doctrine-transport.rst deleted file mode 100644 index ec9a9f2f86d..00000000000 --- a/messenger/doctrine-transport.rst +++ /dev/null @@ -1,214 +0,0 @@ -.. index:: - single: Messenger; Use Doctrine as Transport - -Use Doctrine as transport -========================= - -The Messenger component comes with a Doctrine transport. This lets Doctrine handle the storage of your messages. To use it you need to define the transport as the following: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - transports: - doctrine: doctrine://default - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'doctrine' => 'doctrine://default', - ], - ], - ]); - -The format of the DSN is ``doctrine://``. The connection name is the name you used in the doctrine configuration. If you only use one connection then use ``default``. - -If you have multiple Doctrine connections defined you can choose the desired one. If you have a connection named ``legacy`` the you should use the following DSN : ``doctrine://legacy``. - -Customize Table Name --------------------- - -By default the transport will create a table named ``messenger_messages`` but you can configure it per transport: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - transports: - doctrine: - dsn: doctrine://default?table_name=custom_table_name_for_messages - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'doctrine' => [ - 'dsn' => 'doctrine://default?table_name=custom_table_name_for_messages', - ], - ], - ], - ]); - -Use the same table for different messages ------------------------------------------ - -If you want to store the messages in the same table you can configure the ``queue_name`` option. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - transports: - doctrine: - dsn: doctrine://default?queue_name=custom_queue - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'doctrine' => 'doctrine://default?queue_name=custom_queue', - ], - ], - ]); - -Available options ------------------ - -The transport can be configured via DSN or as options. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - transports: - doctrine_short: doctrine://default?queue_name=custom_queue - doctrine_full: - dsn: doctrine://default - options: - queue_name: custom_queue - - .. code-block:: xml - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'transports' => [ - 'doctrine_short' => 'dsn' => 'doctrine://default?queue_name=custom_queue', - 'doctrine_full' => [ - 'dsn' => 'doctrine://default', - 'options' => [ - 'queue_name' => 'custom_queue' - ] - ], - ], - ], - ]); - -Options defined in the options transport takes precedence over the ones defined in the DSN. - -+-------------------+--------------------------------------------------------------------------------------------------------------------------+--------------------+ -| Option + Description | Default | -+-------------------+--------------------------------------------------------------------------------------------------------------------------+--------------------+ -| table_name | Name of the table | messenger_messages | -| queue_name | Name of the queue | default | -| redeliver_timeout | Timeout before redeliver messages still in handling state (i.e: delivered_at is not null and message is still in table). | 3600 | -| auto_setup | Whether the table should be created automatically during send / get. | true | -+-------------------+--------------------------------------------------------------------------------------------------------------------------+--------------------+ diff --git a/messenger/multiple_buses.rst b/messenger/multiple_buses.rst index bbcc0ba88e2..28d859dd6dd 100644 --- a/messenger/multiple_buses.rst +++ b/messenger/multiple_buses.rst @@ -96,8 +96,14 @@ an **event bus**. The event bus could have zero or more subscribers. ], ]); -This will generate the ``messenger.bus.commands``, ``messenger.bus.queries`` -and ``messenger.bus.events`` services that you can inject in your services. +This will create three new services: + +* ``messenger.bus.commands``: autowireable with the :class:`Symfony\\Component\\Messenger\\MessageBusInterface` + type-hint (because this is the ``default_bus``); + +* ``messenger.bus.queries``: autowireable with the ``MessageBusInterface $messengerBusQueries``; + +* ``messenger.bus.queries``: autowireable with the ``MessageBusInterface $messengerBusEvents``. Type-hints and Auto-wiring -------------------------- From b05f9ca5a97d54c64aab2e5948cef57f22228d1e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 30 May 2019 17:45:04 +0200 Subject: [PATCH 177/499] [HttpClient] add note about getInfo(debug) --- components/http_client.rst | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/components/http_client.rst b/components/http_client.rst index 0cb9cb3c9b9..8fb73058b5b 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -265,6 +265,9 @@ following methods:: // you can get individual info too $startTime = $response->getInfo('start_time'); +.. tip:: + Call ``$response->getInfo('debug')`` to get detailed logs about the HTTP transaction. + .. _http-client-streaming-responses: Streaming Responses @@ -316,17 +319,25 @@ When the HTTP status code of the response is in the 300-599 range (i.e. 3xx, Caching Requests and Responses ------------------------------ -This component provides a special HTTP client via the -:class:`Symfony\\Component\\HttpClient\\CachingHttpClient` class to cache -requests and their responses. The actual HTTP caching is implemented using the -:doc:`HttpKernel component `, so make sure it's -installed in your application. +This component provides a :class:`Symfony\\Component\\HttpClient\\CachingHttpClient` +decorator that allows caching responses and serving them from the local storage +for next requests. The implementation leverages the +:class:`Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache` class under the hood +so that the :doc:`HttpKernel component ` needs to be +installed in your application:: -.. -.. TODO: -.. Show some example of caching requests+responses -.. -.. + use Symfony\Component\HttpClient\HttpClient; + use Symfony\Component\HttpClient\CachingHttpClient; + use Symfony\Component\HttpKernel\HttpCache\Store; + + $store = new Store('/path/to/cache/storage/'); + $client = HttpClient::create(); + $client = new CachingHttpClient($client, $store); + + // this won't hit the network if the resource is already in the cache + $response = $client->request('GET', 'https://example.com/cacheable-resource'); + +``CachingHttpClient`` accepts a third argument to set the options of the ``HttpCache``. Scoping Client -------------- From 02788300526df7fe88c357a74be030844d0a8308 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 30 May 2019 22:09:08 -0400 Subject: [PATCH 178/499] fixing syntax --- components/http_client.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/components/http_client.rst b/components/http_client.rst index 8fb73058b5b..55fe4f530df 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -266,6 +266,7 @@ following methods:: $startTime = $response->getInfo('start_time'); .. tip:: + Call ``$response->getInfo('debug')`` to get detailed logs about the HTTP transaction. .. _http-client-streaming-responses: From 35925dae84fa836abe329a4bb7f74142489bbb95 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Fri, 31 May 2019 07:55:10 +0200 Subject: [PATCH 179/499] Fix `validation.not_compromised_password` option default --- 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 ef0deea0494..610d97836c7 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -2147,13 +2147,13 @@ has been compromised in a data breach. enabled ....... -**type**: ``boolean`` **default**: ``false`` +**type**: ``boolean`` **default**: ``true`` .. versionadded:: 4.3 The ``enabled`` option was introduced in Symfony 4.3. -If you set this option to ``true``, no HTTP requests will be made and the given +If you set this option to ``false``, no HTTP requests will be made and the given password will be considered valid. This is useful when you don't want or can't make HTTP requests, such as in ``dev`` and ``test`` environments or in continuous integration servers. From 29b46ec6fd8e91ac51d15dd439b65ee7a52a90b6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 29 May 2019 14:56:05 +0200 Subject: [PATCH 180/499] Deprecate the templating.* options of FrameworkBundle --- reference/configuration/framework.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index d0e76c61b00..b949a59bdc6 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1850,6 +1850,12 @@ package: templating ~~~~~~~~~~ +.. 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. That's why all the + configuration options defined under ``framework.templating`` are deprecated too. + .. _reference-templating-form: form From 2a750ead452880edabd91172345d17fc439b06f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sat, 24 Nov 2018 15:15:06 +0100 Subject: [PATCH 181/499] Document changes in the deprecation error handler See https://github.com/symfony/symfony/pull/29211 See https://github.com/symfony/symfony/issues/28048 --- bundles/best_practices.rst | 4 +- components/phpunit_bridge.rst | 110 +++++++++++++++++++++++++--------- setup/bundles.rst | 2 +- setup/upgrade_major.rst | 10 ++-- 4 files changed, 90 insertions(+), 36 deletions(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index fb55cf20924..c31db1f6f59 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -197,9 +197,9 @@ of Symfony and the latest beta release: include: # Minimum supported dependencies with the latest and oldest PHP version - php: 7.2 - env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="weak_vendors" + env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="max[internal]=0" - php: 7.0 - env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="weak_vendors" + env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="max[internal]=0" # Test the latest stable release - php: 7.0 diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index e4e934003f8..7792a1e9fde 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -29,7 +29,7 @@ Installation .. code-block:: terminal - $ composer require --dev "symfony/phpunit-bridge:*" + $ composer require --dev symfony/phpunit-bridge .. include:: /components/require_autoload.rst.inc @@ -179,7 +179,7 @@ message, enclosed with ``/``. For example, with: - + @@ -189,39 +189,89 @@ message contains the ``"foobar"`` string. Making Tests Fail ~~~~~~~~~~~~~~~~~ -By default, any non-legacy-tagged or any non-`@-silenced`_ deprecation notices -will make tests fail. Alternatively, setting ``SYMFONY_DEPRECATIONS_HELPER`` to -an arbitrary value (ex: ``320``) will make the tests fails only if a higher -number of deprecation notices is reached (``0`` is the default value). You can -also set the value ``"weak"`` which will make the bridge ignore any deprecation -notices. This is useful to projects that must use deprecated interfaces for -backward compatibility reasons. - -When you maintain a library, having the test suite fail as soon as a dependency -introduces a new deprecation is not desirable, because it shifts the burden of -fixing that deprecation to any contributor that happens to submit a pull -request shortly after a new vendor release is made with that deprecation. To -mitigate this, you can either use tighter requirements, in the hope that -dependencies will not introduce deprecations in a patch version, or even commit -the Composer lock file, which would create another class of issues. Libraries -will often use ``SYMFONY_DEPRECATIONS_HELPER=weak`` because of this. This has -the drawback of allowing contributions that introduce deprecations but: +By default, any non-legacy-tagged or any non-`@-silenced`_ deprecation +notices will make tests fail. Alternatively, you can configure an +arbitrary threshold by setting ``SYMFONY_DEPRECATIONS_HELPER`` to +``max[total]=320`` for instance. It will make the tests fails only if a +higher number of deprecation notices is reached (``0`` is the default +value). + +You can even finer-grained control by using other keys of the ``max`` +array, which are ``internal``, ``direct``, and ``indirect``. The +``SYMFONY_DEPRECATIONS_HELPER`` environment variable accept a +url-encoded string, meaning you can combine thresholds and any other +configuration setting, like this: +``SYMFONY_DEPRECATIONS_HELPER=max[total]=42&max[internal]=0&verbose=0`` + +Internal deprecations +..................... + +When you maintain a library, having the test suite fail as soon as a +dependency introduces a new deprecation is not desirable, because it +shifts the burden of fixing that deprecation to any contributor that +happens to submit a pull request shortly after a new vendor release is +made with that deprecation. To mitigate this, you can either use tighter +requirements, in the hope that dependencies will not introduce +deprecations in a patch version, or even commit the Composer lock file, +which would create another class of issues. Libraries will often use +``SYMFONY_DEPRECATIONS_HELPER=max[total]=999999`` because of this. This +has the drawback of allowing contributions that introduce deprecations +but: * forget to fix the deprecated calls if there are any; * forget to mark appropriate tests with the ``@group legacy`` annotations. -By using the ``"weak_vendors"`` value, deprecations that are triggered outside -the ``vendors`` directory will make the test suite fail, while deprecations -triggered from a library inside it will not, giving you the best of both -worlds. +By using ``SYMFONY_DEPRECATIONS_HELPER=max[internal]=0``, +deprecations that are triggered outside the ``vendors`` directory will +be accounted for seperately, while deprecations triggered from a library +inside it will not (unless you reach 999999 of these), giving you +the best of both worlds. + +Direct and indirect deprecations +................................ + +When working on a project, you might be more interested in +``max[direct]``. Let's say you want to fix deprecations as soon as +they appear. A problem many people experience is that some dependencies +they have tend to lag behind their own dependencies, meaning they do not +fix deprecations as soon as possible, which means there is nothing you +can do to fix those (apart from a pull request on the outdated vendor). +This key allows you to put a threshold on direct deprecations only, +allowing you to notice when *your code* is using deprecated APIs, and to +keep up with the changes. You can of course still use ``max[indirect]`` +if you want to keep indirect deprecations under a given threshold. + +Here is a summary that should help you pick the right configuration: + ++------------------------+-----------------------------------------------------+ +| Value | Recommended situation | ++========================+=====================================================+ +| max[total]=0 | Recommended for actively maintained projects | +| | with little to no dependencies | ++------------------------+-----------------------------------------------------+ +| max[direct]=0 | Recommended for projects with dependencies | +| | that fail to keep up with new deprecations. | ++------------------------+-----------------------------------------------------+ +| max[internal]=0 | Recommended for libraries that use | +| | the deprecation system themselves and | +| | cannot afford to use one of the modes above. | ++------------------------+-----------------------------------------------------+ + +Disabling the verbose output +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, the brige 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. Disabling the Deprecation Helper ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Set the ``SYMFONY_DEPRECATIONS_HELPER`` environment variable to ``disabled`` to -completely disable the deprecation helper. This is useful to make use of the -rest of features provided by this component without getting errors or messages -related to deprecations. +Set the ``SYMFONY_DEPRECATIONS_HELPER`` environment variable to +``disabled=1`` to completely disable the deprecation helper. This is +useful to make use of the rest of features provided by this component +without getting errors or messages related to deprecations. .. _write-assertions-about-deprecations: @@ -247,6 +297,10 @@ 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 ----------------------------------- @@ -287,7 +341,7 @@ Running the following command will display the full stack trace: .. code-block:: terminal - $ SYMFONY_DEPRECATIONS_HELPER='/Doctrine\\Common\\ClassLoader is deprecated\./' ./vendor/bin/simple-phpunit + $ SYMFONY_DEPRECATIONS_HELPER='regex=/Doctrine\\Common\\ClassLoader is deprecated\./' ./vendor/bin/simple-phpunit Time-sensitive Tests -------------------- diff --git a/setup/bundles.rst b/setup/bundles.rst index a83916898c7..53104c6c9ba 100644 --- a/setup/bundles.rst +++ b/setup/bundles.rst @@ -142,7 +142,7 @@ following recommended configuration as the starting point of your own configurat matrix: include: - php: 5.3.3 - env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable' SYMFONY_DEPRECATIONS_HELPER=weak + env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable' SYMFONY_DEPRECATIONS_HELPER=max[total]=999999 - php: 5.6 env: SYMFONY_VERSION='2.7.*' - php: 5.6 diff --git a/setup/upgrade_major.rst b/setup/upgrade_major.rst index b8c00234fc8..16fb2a5f9c7 100644 --- a/setup/upgrade_major.rst +++ b/setup/upgrade_major.rst @@ -97,9 +97,9 @@ done! Sometimes, you can't fix all deprecations (e.g. something was deprecated in 3.4 and you still need to support 3.3). In these cases, you can still - use the bridge to fix as many deprecations as possible and then switch - to the weak test mode to make your tests pass again. You can do this by - using the ``SYMFONY_DEPRECATIONS_HELPER`` env variable: + 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: .. code-block:: xml @@ -108,11 +108,11 @@ done! - + - (you can also execute the command like ``SYMFONY_DEPRECATIONS_HELPER=weak phpunit``). + (you can also execute the command like ``SYMFONY_DEPRECATIONS_HELPER=max[total]=999999 phpunit``). .. _upgrade-major-symfony-composer: From 988badf2f025e0c57b2da5ed8c5d60fd0f68a586 Mon Sep 17 00:00:00 2001 From: Olena Kirichok Date: Sun, 28 Apr 2019 17:40:55 +0200 Subject: [PATCH 182/499] fixup! Document changes in the deprecation error handler --- bundles/best_practices.rst | 4 ++-- components/phpunit_bridge.rst | 27 ++++++++++++++------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index c31db1f6f59..2e1fd28fab8 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -197,9 +197,9 @@ of Symfony and the latest beta release: include: # Minimum supported dependencies with the latest and oldest PHP version - php: 7.2 - env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="max[internal]=0" + env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="max[self]=0" - php: 7.0 - env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="max[internal]=0" + env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="max[self]=0" # Test the latest stable release - php: 7.0 diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 7792a1e9fde..e1edb680771 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -196,12 +196,12 @@ arbitrary threshold by setting ``SYMFONY_DEPRECATIONS_HELPER`` to higher number of deprecation notices is reached (``0`` is the default value). -You can even finer-grained control by using other keys of the ``max`` -array, which are ``internal``, ``direct``, and ``indirect``. The +You can have even finer-grained control by using other keys of the ``max`` +array, which are ``self``, ``direct``, and ``indirect``. The ``SYMFONY_DEPRECATIONS_HELPER`` environment variable accept a url-encoded string, meaning you can combine thresholds and any other configuration setting, like this: -``SYMFONY_DEPRECATIONS_HELPER=max[total]=42&max[internal]=0&verbose=0`` +``SYMFONY_DEPRECATIONS_HELPER=max[total]=42&max[self]=0&verbose=0`` Internal deprecations ..................... @@ -221,7 +221,7 @@ but: * forget to fix the deprecated calls if there are any; * forget to mark appropriate tests with the ``@group legacy`` annotations. -By using ``SYMFONY_DEPRECATIONS_HELPER=max[internal]=0``, +By using ``SYMFONY_DEPRECATIONS_HELPER=max[self]=0``, deprecations that are triggered outside the ``vendors`` directory will be accounted for seperately, while deprecations triggered from a library inside it will not (unless you reach 999999 of these), giving you @@ -234,12 +234,13 @@ When working on a project, you might be more interested in ``max[direct]``. Let's say you want to fix deprecations as soon as they appear. A problem many people experience is that some dependencies they have tend to lag behind their own dependencies, meaning they do not -fix deprecations as soon as possible, which means there is nothing you -can do to fix those (apart from a pull request on the outdated vendor). -This key allows you to put a threshold on direct deprecations only, -allowing you to notice when *your code* is using deprecated APIs, and to -keep up with the changes. You can of course still use ``max[indirect]`` -if you want to keep indirect deprecations under a given threshold. +fix deprecations as soon as possible, which means you should create a pull +request on the outdated vendor, and ignore these deprecations until your +pull request is merged. This key allows you to put a threshold on direct +deprecations only,allowing you to notice when *your code* is using +deprecated APIs, and to keep up with the changes. You can of course +still use ``max[indirect]`` if you want to keep indirect deprecations +under a given threshold. Here is a summary that should help you pick the right configuration: @@ -247,12 +248,12 @@ Here is a summary that should help you pick the right configuration: | Value | Recommended situation | +========================+=====================================================+ | max[total]=0 | Recommended for actively maintained projects | -| | with little to no dependencies | +| | with robust/no dependencies | +------------------------+-----------------------------------------------------+ | max[direct]=0 | Recommended for projects with dependencies | | | that fail to keep up with new deprecations. | +------------------------+-----------------------------------------------------+ -| max[internal]=0 | Recommended for libraries that use | +| max[self]=0 | Recommended for libraries that use | | | the deprecation system themselves and | | | cannot afford to use one of the modes above. | +------------------------+-----------------------------------------------------+ @@ -260,7 +261,7 @@ Here is a summary that should help you pick the right configuration: Disabling the verbose output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -By default, the brige will display a detailed output with the number of +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. From b2a7744c1718f7369e8ecfef6a5579a5f1f29f8f Mon Sep 17 00:00:00 2001 From: Olena Kirichok Date: Sun, 28 Apr 2019 17:47:21 +0200 Subject: [PATCH 183/499] fixup! Document changes in the deprecation error handler --- components/phpunit_bridge.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index e1edb680771..05449843dbc 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -248,12 +248,12 @@ Here is a summary that should help you pick the right configuration: | Value | Recommended situation | +========================+=====================================================+ | max[total]=0 | Recommended for actively maintained projects | -| | with robust/no dependencies | +| | with robust/no dependencies | +------------------------+-----------------------------------------------------+ | max[direct]=0 | Recommended for projects with dependencies | | | that fail to keep up with new deprecations. | +------------------------+-----------------------------------------------------+ -| max[self]=0 | Recommended for libraries that use | +| max[self]=0 | Recommended for libraries that use | | | the deprecation system themselves and | | | cannot afford to use one of the modes above. | +------------------------+-----------------------------------------------------+ From dd7eb0bef3e701984b5481a76c7cc7b9d25559f3 Mon Sep 17 00:00:00 2001 From: Olena Kirichok Date: Mon, 29 Apr 2019 14:05:38 +0200 Subject: [PATCH 184/499] fixup! Document changes in the deprecation error handler --- components/phpunit_bridge.rst | 6 +++--- setup/upgrade_major.rst | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 05449843dbc..a30f5e6e70d 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -212,7 +212,7 @@ shifts the burden of fixing that deprecation to any contributor that happens to submit a pull request shortly after a new vendor release is made with that deprecation. To mitigate this, you can either use tighter requirements, in the hope that dependencies will not introduce -deprecations in a patch version, or even commit the Composer lock file, +deprecations in a patch version, or even commit the ``composer.lock`` file, which would create another class of issues. Libraries will often use ``SYMFONY_DEPRECATIONS_HELPER=max[total]=999999`` because of this. This has the drawback of allowing contributions that introduce deprecations @@ -227,7 +227,7 @@ be accounted for seperately, while deprecations triggered from a library inside it will not (unless you reach 999999 of these), giving you the best of both worlds. -Direct and indirect deprecations +Direct and Indirect Deprecations ................................ When working on a project, you might be more interested in @@ -258,7 +258,7 @@ Here is a summary that should help you pick the right configuration: | | cannot afford to use one of the modes above. | +------------------------+-----------------------------------------------------+ -Disabling the verbose output +Disabling the Verbose Output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, the bridge will display a detailed output with the number of diff --git a/setup/upgrade_major.rst b/setup/upgrade_major.rst index 16fb2a5f9c7..c23db607260 100644 --- a/setup/upgrade_major.rst +++ b/setup/upgrade_major.rst @@ -112,7 +112,11 @@ done! - (you can also execute the command like ``SYMFONY_DEPRECATIONS_HELPER=max[total]=999999 phpunit``). + You can also execute the command like: + + .. code-block:: terminal + + $ SYMFONY_DEPRECATIONS_HELPER=max[total]=999999 phpunit .. _upgrade-major-symfony-composer: From 64141fc17f6fb1bc7f3502029815f5746f96b735 Mon Sep 17 00:00:00 2001 From: Olena Kirichok Date: Fri, 17 May 2019 16:58:40 +0200 Subject: [PATCH 185/499] fixup! Document changes in the deprecation error handler --- 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 c23db607260..d888d24bfbf 100644 --- a/setup/upgrade_major.rst +++ b/setup/upgrade_major.rst @@ -116,7 +116,7 @@ done! .. code-block:: terminal - $ SYMFONY_DEPRECATIONS_HELPER=max[total]=999999 phpunit + $ SYMFONY_DEPRECATIONS_HELPER=max[total]=999999 php ./bin/phpunit .. _upgrade-major-symfony-composer: From 403ad61d81cafcd73e6ba1c30c6fdba1b9439514 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 31 May 2019 10:07:15 +0200 Subject: [PATCH 186/499] Minor tweaks --- components/phpunit_bridge.rst | 75 +++++++++++++++++------------------ 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index a30f5e6e70d..ddc47ed9424 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -192,55 +192,53 @@ Making Tests Fail By default, any non-legacy-tagged or any non-`@-silenced`_ deprecation notices will make tests fail. Alternatively, you can configure an arbitrary threshold by setting ``SYMFONY_DEPRECATIONS_HELPER`` to -``max[total]=320`` for instance. It will make the tests fails only if a +``max[total]=320`` for instance. It will make the tests fails only if a higher number of deprecation notices is reached (``0`` is the default value). You can have even finer-grained control by using other keys of the ``max`` array, which are ``self``, ``direct``, and ``indirect``. The -``SYMFONY_DEPRECATIONS_HELPER`` environment variable accept a -url-encoded string, meaning you can combine thresholds and any other -configuration setting, like this: -``SYMFONY_DEPRECATIONS_HELPER=max[total]=42&max[self]=0&verbose=0`` +``SYMFONY_DEPRECATIONS_HELPER`` environment variable accepts an URL-encoded +string, meaning you can combine thresholds and any other configuration setting, +like this: ``SYMFONY_DEPRECATIONS_HELPER=max[total]=42&max[self]=0&verbose=0`` Internal deprecations ..................... -When you maintain a library, having the test suite fail as soon as a -dependency introduces a new deprecation is not desirable, because it -shifts the burden of fixing that deprecation to any contributor that -happens to submit a pull request shortly after a new vendor release is -made with that deprecation. To mitigate this, you can either use tighter -requirements, in the hope that dependencies will not introduce -deprecations in a patch version, or even commit the ``composer.lock`` file, -which would create another class of issues. Libraries will often use -``SYMFONY_DEPRECATIONS_HELPER=max[total]=999999`` because of this. This -has the drawback of allowing contributions that introduce deprecations -but: +When you maintain a library, having the test suite fail as soon as a dependency +introduces a new deprecation is not desirable, because it shifts the burden of +fixing that deprecation to any contributor that happens to submit a pull request +shortly after a new vendor release is made with that deprecation. + +To mitigate this, you can either use tighter requirements, in the hope that +dependencies will not introduce deprecations in a patch version, or even commit +the ``composer.lock`` file, which would create another class of issues. +Libraries will often use ``SYMFONY_DEPRECATIONS_HELPER=max[total]=999999`` +because of this. This has the drawback of allowing contributions that introduce +deprecations but: * forget to fix the deprecated calls if there are any; * forget to mark appropriate tests with the ``@group legacy`` annotations. -By using ``SYMFONY_DEPRECATIONS_HELPER=max[self]=0``, -deprecations that are triggered outside the ``vendors`` directory will -be accounted for seperately, while deprecations triggered from a library -inside it will not (unless you reach 999999 of these), giving you -the best of both worlds. +By using ``SYMFONY_DEPRECATIONS_HELPER=max[self]=0``, deprecations that are +triggered outside the ``vendors`` directory will be accounted for seperately, +while deprecations triggered from a library inside it will not (unless you reach +999999 of these), giving you the best of both worlds. Direct and Indirect Deprecations ................................ -When working on a project, you might be more interested in -``max[direct]``. Let's say you want to fix deprecations as soon as -they appear. A problem many people experience is that some dependencies -they have tend to lag behind their own dependencies, meaning they do not -fix deprecations as soon as possible, which means you should create a pull -request on the outdated vendor, and ignore these deprecations until your -pull request is merged. This key allows you to put a threshold on direct -deprecations only,allowing you to notice when *your code* is using -deprecated APIs, and to keep up with the changes. You can of course -still use ``max[indirect]`` if you want to keep indirect deprecations -under a given threshold. +When working on a project, you might be more interested in ``max[direct]``. +Let's say you want to fix deprecations as soon as they appear. A problem many +developers experience is that some dependencies they have tend to lag behind +their own dependencies, meaning they do not fix deprecations as soon as +possible, which means you should create a pull request on the outdated vendor, +and ignore these deprecations until your pull request is merged. + +The ``max[direct]`` config allows you to put a threshold on direct deprecations +only, allowing you to notice when *your code* is using deprecated APIs, and to +keep up with the changes. You can still use ``max[indirect]`` if you want to +keep indirect deprecations under a given threshold. Here is a summary that should help you pick the right configuration: @@ -262,17 +260,16 @@ Disabling the Verbose Output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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. +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. Disabling the Deprecation Helper ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Set the ``SYMFONY_DEPRECATIONS_HELPER`` environment variable to -``disabled=1`` to completely disable the deprecation helper. This is -useful to make use of the rest of features provided by this component -without getting errors or messages related to deprecations. +Set the ``SYMFONY_DEPRECATIONS_HELPER`` environment variable to ``disabled=1`` +to completely disable the deprecation helper. This is useful to make use of the +rest of features provided by this component without getting errors or messages +related to deprecations. .. _write-assertions-about-deprecations: From d5e3496472054fbe4cd2dd9f54d3c9095582db06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 11 Mar 2019 12:57:26 +0100 Subject: [PATCH 187/499] [Validator][Doctrine] Add docs for automatic validation --- doctrine.rst | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/doctrine.rst b/doctrine.rst index 806a6a33209..ec6447811e4 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -347,9 +347,9 @@ and save it! class ProductController extends AbstractController { /** - * @Route("/product", name="product") + * @Route("/product", name="create_product") */ - public function index() + public function createProduct(): Response { // you can fetch the EntityManager via $this->getDoctrine() // or you can add an argument to your action: index(EntityManagerInterface $entityManager) @@ -412,6 +412,76 @@ Take a look at the previous example in more detail: Whether you're creating or updating objects, the workflow is always the same: Doctrine is smart enough to know if it should INSERT or UPDATE your entity. +Validating Objects +------------------ + +:doc:`The Symfony validator ` reuses Doctrine metadata +to perform some basic validation tasks:: + + // src/Controller/ProductController.php + namespace App\Controller; + + // ... + use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\Validator\Validator\ValidatorInterface; + + use App\Entity\Product; + + class ProductController extends AbstractController + { + /** + * @Route("/product", name="create_product") + */ + public function createProduct(ValidatorInterface $validator): Response + { + $product = new Product(); + $product->setName(null); // The column in database isn't nullable + $product->setPrice('1999'); // Type mismatch, an integer is expected + + // ... + + $errors = $validator->validate($product); + if (count($errors) > 0) { + return new Response((string) $errors, 400); + } + + // Will not be reached in this example + $entityManager = $this->getDoctrine()->getManager(); + $entityManager->persist($product); + $entityManager->flush(); + + return new Response('Saved new product with id '.$product->getId()); + } + } + +The following table summarizes the mapping between Doctrine metadata and +the corresponding validation constraints: + ++--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| Doctrine attribute | Validation constraint | Notes | ++====================+===========================================================+=========================================================================+ +| ``nullable=true`` | :doc:`NotNull ` | Relies on :doc:`the PropertyInfo component ` | ++--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| ``type`` | :doc:`Type ` | Relies on :doc:`the PropertyInfo component ` | ++--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| ``unique=true`` | :doc:`UniqueEntity ` | | ++--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ +| ``length`` | :doc:`Length ` | | ++--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ + +Because :doc:`the Form component ` as well as `API Platform`_ +internally use the Validator Component, all your forms +and web APIs will also automatically benefit from these default constraints. + +.. versionadded:: 4.3 + + The automatic validation has been added in Symfony 4.3. + +.. tip:: + + Don't forget to add :doc:`more precise validation constraints ` + to ensure that data provided by the user is correct. + Fetching Objects from the Database ---------------------------------- @@ -812,3 +882,4 @@ Learn more .. _`ParamConverter`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html .. _`limit of 767 bytes for the index key prefix`: https://dev.mysql.com/doc/refman/5.6/en/innodb-restrictions.html .. _`Doctrine screencast series`: https://symfonycasts.com/screencast/symfony-doctrine +.. _`API Platform`: https://api-platform.com/docs/core/validation/ From 3da08e3815e3421b885dbee86418d7a3452a2fd3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 31 May 2019 10:49:39 +0200 Subject: [PATCH 188/499] Minor reword --- doctrine.rst | 67 ++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/doctrine.rst b/doctrine.rst index 82c5cebf0d6..ad6c180e0d2 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -358,7 +358,7 @@ and save it:: public function createProduct(): Response { // you can fetch the EntityManager via $this->getDoctrine() - // or you can add an argument to your action: index(EntityManagerInterface $entityManager) + // or you can add an argument to the action: createProduct(EntityManagerInterface $entityManager) $entityManager = $this->getDoctrine()->getManager(); $product = new Product(); @@ -421,8 +421,8 @@ is smart enough to know if it should INSERT or UPDATE your entity. Validating Objects ------------------ -:doc:`The Symfony validator ` reuses Doctrine metadata -to perform some basic validation tasks:: +:doc:`The Symfony validator ` reuses Doctrine metadata to perform +some basic validation tasks:: // src/Controller/ProductController.php namespace App\Controller; @@ -441,8 +441,10 @@ to perform some basic validation tasks:: public function createProduct(ValidatorInterface $validator): Response { $product = new Product(); - $product->setName(null); // The column in database isn't nullable - $product->setPrice('1999'); // Type mismatch, an integer is expected + // This will trigger an error: the column isn't nullable in the database + $product->setName(null); + // This will trigger a type mismatch error: an integer is expected + $product->setPrice('1999'); // ... @@ -451,43 +453,42 @@ to perform some basic validation tasks:: return new Response((string) $errors, 400); } - // Will not be reached in this example - $entityManager = $this->getDoctrine()->getManager(); - $entityManager->persist($product); - $entityManager->flush(); - - return new Response('Saved new product with id '.$product->getId()); + // ... } } +Although the ``Product`` entity doesn't define any explicit +:doc:`validation configuration `, Symfony introspects the Doctrine +mapping configuration to infer some validation rules. For example, given that +the ``name`` property can't be ``null`` in the database, a +:doc:`NotNull constraint ` is added automatically +to the property (if it doesn't contain that constraint already). + The following table summarizes the mapping between Doctrine metadata and -the corresponding validation constraints: - -+--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ -| Doctrine attribute | Validation constraint | Notes | -+====================+===========================================================+=========================================================================+ -| ``nullable=true`` | :doc:`NotNull ` | Relies on :doc:`the PropertyInfo component ` | -+--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ -| ``type`` | :doc:`Type ` | Relies on :doc:`the PropertyInfo component ` | -+--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ -| ``unique=true`` | :doc:`UniqueEntity ` | | -+--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ -| ``length`` | :doc:`Length ` | | -+--------------------+-----------------------------------------------------------+-------------------------------------------------------------------------+ - -Because :doc:`the Form component ` as well as `API Platform`_ -internally use the Validator Component, all your forms -and web APIs will also automatically benefit from these default constraints. +the corresponding validation constraints added automatically by Symfony: + +================== ========================================================= ===== +Doctrine attribute Validation constraint Notes +================== ========================================================= ===== +``nullable=false`` :doc:`NotNull ` Requires installing the :doc:`PropertyInfo component ` +``type`` :doc:`Type ` Requires installing the :doc:`PropertyInfo component ` +``unique=true`` :doc:`UniqueEntity ` +``length`` :doc:`Length ` +================== ========================================================= ===== + +Because :doc:`the Form component ` as well as `API Platform`_ internally +use the Validator component, all your forms and web APIs will also automatically +benefit from these automatic validation constraints. + +This automatic validation is a nice feature to improve your productivity, but it +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. -.. tip:: - - Don't forget to add :doc:`more precise validation constraints ` - to ensure that data provided by the user is correct. - Fetching Objects from the Database ---------------------------------- From c2e92a5dd0a3ea3488ea5ba441dedf5ee0dd8d63 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 30 May 2019 11:16:13 -0400 Subject: [PATCH 189/499] deprecating Swift Mailer and moving all docs into one spot and moving many docs from mime to Mailer and writing it Co-Authored-By: Wouter J Co-Authored-By: Ricardo de Vries Co-Authored-By: Antoine Makdessi --- _build/redirection_map | 3 + components/mime.rst | 426 ++-------------- console/command_in_controller.rst | 2 +- contributing/documentation/format.rst | 2 +- email.rst | 505 +++++++++++++++++- email/dev_environment.rst | 252 --------- email/spool.rst | 164 ------ email/testing.rst | 85 ---- index.rst | 1 + mailer.rst | 649 ++++++++++++++++++++++++ reference/configuration/swiftmailer.rst | 2 +- setup/flex.rst | 2 + 12 files changed, 1194 insertions(+), 899 deletions(-) delete mode 100644 email/dev_environment.rst delete mode 100644 email/spool.rst delete mode 100644 email/testing.rst create mode 100644 mailer.rst diff --git a/_build/redirection_map b/_build/redirection_map index 7e8c54bd737..9de3db1ba4d 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -417,3 +417,6 @@ /workflow/state-machines /workflow/introduction /workflow/usage /workflow /introduction/from_flat_php_to_symfony2 /introduction/from_flat_php_to_symfony +/email/dev_environment /mailer +/email/spool /mailer +/email/testing /mailer diff --git a/components/mime.rst b/components/mime.rst index 8c822772b2a..5b258080bcc 100644 --- a/components/mime.rst +++ b/components/mime.rst @@ -58,128 +58,64 @@ methods to compose the entire email message:: This only purpose of this component is to create the email messages. Use the :doc:`Mailer component ` to actually send them. In Symfony -applications, it's easier to use the :doc:`Mailer integration `. +applications, it's easier to use the :doc:`Mailer integration `. -Email Addresses ---------------- +Most of the details about how to create Email objects, including Twig integration, +can be found in the :doc:`Mailer documentation `. -All the methods that require email addresses (``from()``, ``to()``, etc.) accept -both strings and objects:: - - // ... - use Symfony\Component\Mime\Address; - use Symfony\Component\Mime\NamedAddress; - - $email = (new Email()) - // email address as a simple string - ->from('fabien@symfony.com') - - // email address as an object - ->from(new Address('fabien@symfony.com')) - - // email address as an object (email clients will display the name - // instead of the email address) - ->from(new NamedAddress('fabien@symfony.com', 'Fabien')) - - // ... - ; - -Multiple addresses are defined with the ``addXXX()`` methods:: - - $email = (new Email()) - ->to('foo@example.com') - ->addTo('bar@example.com') - ->addTo('baz@example.com') - - // ... - ; - -Alternatively, you can pass multiple addresses to each method:: - - $toAddresses = ['foo@example.com', new Address('bar@example.com')]; - - $email = (new Email()) - ->to(...$toAddresses) - ->cc('cc1@example.com', 'cc2@example.com') - - // ... - ; - -Message Contents +Twig Integration ---------------- -The text and HTML contents of the email messages can be strings (usually the -result of rendering some template) or PHP resources:: +The Mime component comes with excellent integration with Twig, allowing you to +create messages from Twig templates, embed images, inline CSS and more. Details +on how to use those features can be found in the Mailer documentation: +:ref:`Twig: HTML & CSS `. - $email = (new Email()) - // ... - // simple contents defined as a string - ->text('Lorem ipsum...') - ->html('

Lorem ipsum...

') +But if you're using the Mime component without the Symfony framework, you'll need +to handle a few setup details. - // contents obtained from a PHP resource - ->text(fopen('/path/to/emails/user_signup.txt', 'r')) - ->html(fopen('/path/to/emails/user_signup.html', 'r')) - ; +Twig Setup +~~~~~~~~~~ -.. tip:: +To integrate with Twig, use the :class:`Symfony\\Bridge\\Twig\\Mime\\BodyRenderer` +class to render the template and update the email message contents with the results:: - You can also use Twig templates to render the HTML and text contents. Read - the :ref:`mime-component-twig-integration` section later in this article to - learn more. + // ... + use Symfony\Bridge\Twig\Mime\BodyRenderer; + use Twig\Environment; + use Twig\Loader\FilesystemLoader; -Embedding Images ----------------- + // when using the Mime component inside a full-stack Symfony application, you + // don't need to do this Twig setup. You only have to inject the 'twig' service + $loader = new FilesystemLoader(__DIR__.'/templates'); + $twig = new Environment($loader); -If you want to display images inside your email contents, you must embed them -instead of adding them as attachments. When using Twig to render the email -contents, as explained :ref:`later in this article ` -the images are embedded automatically. Otherwise, you need to embed them manually. + $renderer = new BodyRenderer($twig); + // this updates the $email object contents with the result of rendering + // the template defined earlier with the given context + $renderer->render($email); -First, use the ``embed()`` or ``embedFromPath()`` method to add an image from a -file or resource:: +Inlining CSS Styles (and other Extensions) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - $email = (new Email()) - // ... - // get the image contents from a PHP resource - ->embed(fopen('/path/to/images/logo.png', 'r'), 'logo') - // get the image contents from an existing file - ->embedFromPath('/path/to/images/signature.gif', 'footer-signature') - ; +To use the :ref:`inline_css ` filter, first install the Twig +extension: -The second optional argument of both methods is the image name ("Content-ID" in -the MIME standard). Its value is an arbitrary string used later to reference the -images inside the HTML contents:: - - $email = (new Email()) - // ... - ->embed(fopen('/path/to/images/logo.png', 'r'), 'logo') - ->embedFromPath('/path/to/images/signature.gif', 'footer-signature') - // reference images using the syntax 'cid:' + "image embed name" - ->html(' ... ...') - ; +.. code-block:: terminal -File Attachments ----------------- + $ composer require twig/cssinliner-extension -Use the ``attachFromPath()`` method to attach files that exist in your file system:: +Now, enable the extension:: - $email = (new Email()) - // ... - ->attachFromPath('/path/to/documents/terms-of-use.pdf') - // optionally you can tell email clients to display a custom name for the file - ->attachFromPath('/path/to/documents/privacy.pdf', 'Privacy Policy') - // optionally you can provide an explicit MIME type (otherwise it's guessed) - ->attachFromPath('/path/to/documents/contract.doc', 'Contract', 'application/msword') - ; + // ... + use Twig\CssInliner\CssInlinerExtension; -Alternatively you can use the ``attach()`` method to attach contents generated -with PHP resources:: + $loader = new FilesystemLoader(__DIR__.'/templates'); + $twig = new Environment($loader); + $twig->addExtension(new CssInlinerExtension()); - $email = (new Email()) - // ... - ->attach(fopen('/path/to/documents/contract.doc', 'r')) - ; +The same process should be used for enabling other extensions, like the +:ref:`MarkdownExtension ` and :ref:`InkyExtension `. Creating Raw Email Messages --------------------------- @@ -287,285 +223,6 @@ from their serialized contents:: // later, recreate the original message to actually send it $message = new RawMessage(unserialize($serializedEmail)); -.. _mime-component-twig-integration: - -Twig Integration ----------------- - -The Mime component integrates with the :doc:`Twig template engine ` -to provide advanced features such as CSS style inlining and support for HTML/CSS -frameworks to create complex HTML email messages. - -Rendering Email Contents with Twig -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you define the contents of your email in Twig templates, use the -:class:`Symfony\\Bridge\\Twig\\Mime\\TemplatedEmail` class. This class extends -from the :class:`Symfony\\Component\\Mime\\Email` class explained above and adds -some utility methods for Twig templates:: - - use Symfony\Bridge\Twig\Mime\TemplatedEmail; - - $email = (new TemplatedEmail()) - ->from('fabien@symfony.com') - ->to('foo@example.com') - // ... - - // this method defines the path of the Twig template to render - ->htmlTemplate('messages/user/signup.html.twig') - - // this method defines the parameters (name => value) passed to templates - ->context([ - 'expiration_date' => new \DateTime('+7 days'), - 'username' => 'foo', - ]) - ; - -Once the email object has been created, you must set up Twig to define where -templates are located and then, use the -:class:`Symfony\\Bridge\\Twig\\Mime\\BodyRenderer` class to render the template -and update the email message contents with the results. All this is done -automatically when using the component inside a Symfony application:: - - // ... - use Symfony\Bridge\Twig\Mime\BodyRenderer; - use Twig\Environment; - use Twig\Loader\FilesystemLoader; - - // when using the Mime component inside a full-stack Symfony application, you - // don't need to do this Twig setup. You only have to inject the 'twig' service - $loader = new FilesystemLoader(__DIR__.'/templates'); - $twig = new Environment($loader); - - $renderer = new BodyRenderer($twig); - // this updates the $email object contents with the result of rendering - // the template defined earlier with the given context - $renderer->render($email); - -The last step is to create the Twig template used to render the contents: - -.. code-block:: html+twig - -

Welcome {{ username }}!

- -

You signed up to our site using the following email:

-

{{ email.to }}

- -

Click here to activate your account

- -The Twig template has access to any of the parameters passed in the ``context`` -method of the ``TemplatedEmail`` class and also to a special variable called -``email``. This variable is an instance of the -:class:`Symfony\\Bridge\\Twig\\Mime\\WrappedTemplatedEmail` class which gives -access to some of the email message properties. - -When the text content of the message is not defined explicitly, the -``BodyRenderer()`` class generates it automatically converting the HTML contents -into text. If you have `league/html-to-markdown`_ installed in your application, -it uses that to turn HTML into Markdown. Otherwise, it applies the -:phpfunction:`strip_tags` PHP function to the original HTML contents. - -If you prefer to define the text content yourself, use the ``text()`` method -explained in the previous sections or the ``textTemplate()`` method provided by -the ``TemplatedEmail`` class:: - - use Symfony\Bridge\Twig\Mime\TemplatedEmail; - - $email = (new TemplatedEmail()) - ->from('fabien@symfony.com') - ->to('foo@example.com') - // ... - - ->textTemplate('messages/user/signup.txt.twig') - ->htmlTemplate('messages/user/signup.html.twig') - - ->context([ - 'expiration_date' => new \DateTime('+7 days'), - 'username' => 'foo', - ]) - ; - -.. _embedding-images-in-emails-with-twig: - -Embedding Images in Emails with Twig -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Instead of dealing with the ```` syntax explained in the -previous sections, when using Twig to render email contents you can refer to -image files as usual. First, define a Twig namespace called ``images`` to -simplify things later:: - - // ... - - $templateLoader = new FilesystemLoader(__DIR__.'/templates'); - $templateLoader->addPath(__DIR__.'/images', 'images'); - $twig = new Environment($templateLoader); - -Now, use the special ``email.image()`` Twig helper to embed the images inside -the email contents: - -.. code-block:: html+twig - - {# '@images/' refers to the Twig namespace defined earlier #} - - -

Welcome {{ username }}!

- {# ... #} - -Inlining CSS Styles in Emails with Twig -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Designing the HTML contents of an email is very different from designing a -normal HTML page. For starters, most email clients only support a subset of all -CSS features. In addition, popular email clients such as Gmail don't support -defining styles inside ```` sections and you must **inline -all the CSS styles**. - -CSS inlining means that every HTML tag must define a ``style`` attribute with -all its CSS styles. This not only increases the email byte size significantly -but also makes it impossible to manage for complex emails. That's why Twig -provides a ``CssInlinerExtension`` that automates everything for you. First, -install the Twig extension in your application: - -.. code-block:: terminal - - $ composer require twig/cssinliner-extension - -Now, enable the extension (this is done automatically in Symfony applications):: - - // ... - use Twig\CssInliner\CssInlinerExtension; - - $loader = new FilesystemLoader(__DIR__.'/templates'); - $twig = new Environment($loader); - $twig->addExtension(new CssInlinerExtension()); - -Finally, wrap the entire template contents with the ``inline_css`` filter: - -.. code-block:: html+twig - - {% filter inline_css %} - - -

Welcome {{ username }}!

- {# ... #} - {% endfilter %} - -You can also define some or all CSS styles in external files and pass them as -arguments of the filter: - -.. code-block:: html+twig - - {# '@css/' refers to the Twig namespace defined earlier #} - {% filter inline_css('@css/mailing.css') %} - - -

Welcome {{ username }}!

- {# ... #} - {% endfilter %} - -Rendering Markdown Contents in Emails with Twig -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Twig provides another extension called ``MarkdownExtension`` that lets you -define the email contents using the `Markdown syntax`_. In addition to the -extension, you must also install a Markdown conversion library (the extension is -compatible with all the popular libraries): - -.. code-block:: terminal - - $ composer require twig/markdown-extension - - # these libraries are compatible too: erusev/parsedown, michelf/php-markdown - $ composer require league/commonmark - -Now, enable the extension (this is done automatically in Symfony applications):: - - // ... - use Twig\Markdown\MarkdownExtension; - - $loader = new FilesystemLoader(__DIR__.'/templates'); - $twig = new Environment($loader); - $twig->addExtension(new MarkdownExtension()); - -Finally, use the ``markdown`` filter to convert parts or the entire email -contents from Markdown to HTML: - -.. code-block:: twig - - {% filter markdown %} - Welcome {{ username }}! - ======================= - - You signed up to our site using the following email: - `{{ email.to }}` - - [Click here to activate your account]({{ url('...') }}) - {% endfilter %} - -Using the Inky Email Templating Language with Twig -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Creating beautifully designed emails that work on every email client is so -complex that there are HTML/CSS frameworks dedicated to that. One of the most -popular frameworks is called `Inky`_. It defines a syntax based on some simple -tags which are later transformed into the real HTML code sent to users: - -.. code-block:: html - - - - - This is a column. - - - -Twig provides integration with Inky via the ``InkyExtension``. First, install -the extension in your application: - -.. code-block:: terminal - - $ composer require twig/inky-extension - -Now, enable the extension (this is done automatically in Symfony applications):: - - // ... - use Twig\Inky\InkyExtension; - - $loader = new FilesystemLoader(__DIR__.'/templates'); - $twig = new Environment($loader); - $twig->addExtension(new InkyExtension()); - -Finally, use the ``inky`` filter to convert parts or the entire email -contents from Inky to HTML: - -.. code-block:: html+twig - - {% filter inky %} - - - - -

Welcome {{ username }}!

-
- - {# ... #} -
-
- {% endfilter %} - -You can combine all filters to create complex email messages: - -.. code-block:: twig - - {% filter inky|inline_css(source('@zurb/stylesheets/main.css')) %} - {# ... #} - {% endfilter %} - MIME Types Utilities -------------------- @@ -638,8 +295,5 @@ You can register your own MIME type guesser by creating a class that implements } .. _`MIME`: https://en.wikipedia.org/wiki/MIME -.. _`league/html-to-markdown`: https://github.com/thephpleague/html-to-markdown -.. _`Markdown syntax`: https://commonmark.org/ -.. _`Inky`: https://foundation.zurb.com/emails.html .. _`MIME types`: https://en.wikipedia.org/wiki/Media_type .. _`fileinfo extension`: https://php.net/fileinfo diff --git a/console/command_in_controller.rst b/console/command_in_controller.rst index d738484c6b8..6559ae15c0a 100644 --- a/console/command_in_controller.rst +++ b/console/command_in_controller.rst @@ -21,7 +21,7 @@ their code. Instead, you can execute the command directly. overhead. Imagine you want to send spooled Swift Mailer messages by -:doc:`using the swiftmailer:spool:send command `. +:doc:`using the swiftmailer:spool:send command `. Run this command from inside your controller via:: // src/Controller/SpoolController.php diff --git a/contributing/documentation/format.rst b/contributing/documentation/format.rst index 9fcdebd69f7..493be6b3fce 100644 --- a/contributing/documentation/format.rst +++ b/contributing/documentation/format.rst @@ -131,7 +131,7 @@ If you want to modify that title, use this alternative syntax: .. code-block:: rst - :doc:`Spooling Email ` + :doc:`Doctrine Associations ` .. note:: diff --git a/email.rst b/email.rst index 29bb7a1d171..f1ef02ef9bd 100644 --- a/email.rst +++ b/email.rst @@ -1,8 +1,13 @@ .. index:: single: Emails -How to Send an Email -==================== +Swift Mailer +============ + +.. note:: + + In Symfony 4.3, the :doc:`Mailer ` component was introduced and can + be used instead of Swift Mailer. Symfony provides a mailer feature based on the popular `Swift Mailer`_ library via the `SwiftMailerBundle`_. This mailer supports sending messages with your @@ -158,16 +163,498 @@ file. For example, for `Amazon SES`_ (Simple Email Service): Use the same technique for other mail services, as most of the time there is nothing more to it than configuring an SMTP endpoint. -Learn more ----------- +How to Work with Emails during Development +------------------------------------------ + +When developing an application which sends email, you will often +not want to actually send the email to the specified recipient during +development. If you are using the SwiftmailerBundle with Symfony, you +can achieve this through configuration settings without having to make +any changes to your application's code at all. There are two main choices +when it comes to handling email during development: (a) disabling the +sending of email altogether or (b) sending all email to a specific +address (with optional exceptions). + +Disabling Sending +~~~~~~~~~~~~~~~~~ + +You can disable sending email by setting the ``disable_delivery`` option to +``true``, which is the default value used by Symfony in the ``test`` environment +(email messages will continue to be sent in the other environments): + +.. 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", + ]); + +.. _sending-to-a-specified-address: + +Sending to a Specified Address(es) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also choose to have all email sent to a specific address or a list of addresses, instead +of the address actually specified when sending the message. This can be done +via the ``delivery_addresses`` option: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/dev/swiftmailer.yaml + swiftmailer: + delivery_addresses: ['dev@example.com'] + + .. code-block:: xml + + + + + + + dev@example.com + + + + .. code-block:: php + + // config/packages/dev/swiftmailer.php + $container->loadFromExtension('swiftmailer', [ + 'delivery_addresses' => ['dev@example.com'], + ]); + +Now, suppose you're sending an email to ``recipient@example.com`` in a controller:: + + public function index($name, \Swift_Mailer $mailer) + { + $message = (new \Swift_Message('Hello Email')) + ->setFrom('send@example.com') + ->setTo('recipient@example.com') + ->setBody( + $this->renderView( + 'HelloBundle:Hello:email.txt.twig', + ['name' => $name] + ) + ) + ; + $mailer->send($message); + + return $this->render(...); + } + +In the ``dev`` environment, the email will instead be sent to ``dev@example.com``. +Swift Mailer will add an extra header to the email, ``X-Swift-To``, containing +the replaced address, so you can still see who it would have been sent to. + +.. note:: + + In addition to the ``to`` addresses, this will also stop the email being + sent to any ``CC`` and ``BCC`` addresses set for it. Swift Mailer will add + additional headers to the email with the overridden addresses in them. + These are ``X-Swift-Cc`` and ``X-Swift-Bcc`` for the ``CC`` and ``BCC`` + addresses respectively. + +.. _sending-to-a-specified-address-but-with-exceptions: + +Sending to a Specified Address but with Exceptions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Suppose you want to have all email redirected to a specific address, +(like in the above scenario to ``dev@example.com``). But then you may want +email sent to some specific email addresses to go through after all, and +not be redirected (even if it is in the dev environment). This can be done +by adding the ``delivery_whitelist`` option: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/dev/swiftmailer.yaml + swiftmailer: + delivery_addresses: ['dev@example.com'] + delivery_whitelist: + # all email addresses matching these regexes will be delivered + # like normal, as well as being sent to dev@example.com + - '/@specialdomain\.com$/' + - '/^admin@mydomain\.com$/' + + .. code-block:: xml + + + + + + + + /@specialdomain\.com$/ + /^admin@mydomain\.com$/ + dev@example.com + + + + .. code-block:: php + + // config/packages/dev/swiftmailer.php + $container->loadFromExtension('swiftmailer', [ + 'delivery_addresses' => ["dev@example.com"], + 'delivery_whitelist' => [ + // all email addresses matching these regexes will be delivered + // like normal, as well as being sent to dev@example.com + '/@specialdomain\.com$/', + '/^admin@mydomain\.com$/', + ], + ]); + +In the above example all email messages will be redirected to ``dev@example.com`` +and messages sent to the ``admin@mydomain.com`` address or to any email address +belonging to the domain ``specialdomain.com`` will also be delivered as normal. + +.. caution:: + + The ``delivery_whitelist`` option is ignored unless the ``delivery_addresses`` option is defined. + +Viewing from the Web Debug Toolbar +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can view any email sent during a single response when you are in the +``dev`` environment using the web debug toolbar. The email icon in the toolbar +will show how many emails were sent. If you click it, a report will open +showing the details of the sent emails. + +If you're sending an email and then immediately redirecting to another page, +the web debug toolbar will not display an email icon or a report on the next +page. + +Instead, you can set the ``intercept_redirects`` option to ``true`` in the +``dev`` environment, which will cause the redirect to stop and allow you to open +the report with details of the sent emails. + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/dev/web_profiler.yaml + web_profiler: + intercept_redirects: true + + .. code-block:: xml + + + + + + + + + .. code-block:: php + + // config/packages/dev/web_profiler.php + $container->loadFromExtension('web_profiler', [ + 'intercept_redirects' => 'true', + ]); + +.. tip:: + + Alternatively, you can open the profiler after the redirect and search + by the submit URL used on the previous request (e.g. ``/contact/handle``). + The profiler's search feature allows you to load the profiler information + for any past requests. + +.. tip:: + + In addition to the features provided by Symfony, there are applications that + can help you test emails during application development, like `MailCatcher`_ + and `MailHog`_. + +How to Spool Emails +------------------- + +The default behavior of the Symfony mailer is to send the email messages +immediately. You may, however, want to avoid the performance hit of the +communication to the email server, which could cause the user to wait for the +next page to load while the email is sending. This can be avoided by choosing to +"spool" the emails instead of sending them directly. + +This makes the mailer to not attempt to send the email message but instead save +it somewhere such as a file. Another process can then read from the spool and +take care of sending the emails in the spool. Currently only spooling to file or +memory is supported. + +.. _email-spool-memory: + +Spool Using Memory +~~~~~~~~~~~~~~~~~~ + +When you use spooling to store the emails to memory, they will get sent right +before the kernel terminates. This means the email only gets sent if the whole +request got executed without any unhandled exception or any errors. To configure +this spool, use the following configuration: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/swiftmailer.yaml + swiftmailer: + # ... + spool: { type: memory } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/packages/swiftmailer.php + $container->loadFromExtension('swiftmailer', [ + // ... + 'spool' => ['type' => 'memory'], + ]); + +.. _spool-using-a-file: + +Spool Using Files +~~~~~~~~~~~~~~~~~ + +When you use the filesystem for spooling, Symfony creates a folder in the given +path for each mail service (e.g. "default" for the default service). This folder +will contain files for each email in the spool. So make sure this directory is +writable by Symfony (or your webserver/php)! + +In order to use the spool with files, use the following configuration: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/swiftmailer.yaml + swiftmailer: + # ... + spool: + type: file + path: /path/to/spooldir + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // config/packages/swiftmailer.php + $container->loadFromExtension('swiftmailer', [ + // ... + + 'spool' => [ + 'type' => 'file', + 'path' => '/path/to/spooldir', + ], + ]); + +.. tip:: + + If you want to store the spool somewhere with your project directory, + remember that you can use the ``%kernel.project_dir%`` parameter to reference + the project's root: + + .. code-block:: yaml + + path: '%kernel.project_dir%/var/spool' + +Now, when your app sends an email, it will not actually be sent but instead +added to the spool. Sending the messages from the spool is done separately. +There is a console command to send the messages in the spool: + +.. code-block:: terminal + + $ APP_ENV=prod php bin/console swiftmailer:spool:send + +It has an option to limit the number of messages to be sent: + +.. code-block:: terminal + + $ APP_ENV=prod php bin/console swiftmailer:spool:send --message-limit=10 + +You can also set the time limit in seconds: + +.. code-block:: terminal + + $ APP_ENV=prod php bin/console swiftmailer:spool:send --time-limit=10 + +In practice you will not want to run this manually. Instead, the console command +should be triggered by a cron job or scheduled task and run at a regular +interval. + +.. caution:: + + When you create a message with SwiftMailer, it generates a ``Swift_Message`` + class. If the ``swiftmailer`` service is lazy loaded, it generates instead a + proxy class named ``Swift_Message_``. + + If you use the memory spool, this change is transparent and has no impact. + But when using the filesystem spool, the message class is serialized in + a file with the randomized class name. The problem is that this random + class name changes on every cache clear. So if you send a mail and then you + clear the cache, the message will not be unserializable. + + On the next execution of ``swiftmailer:spool:send`` an error will raise because + the class ``Swift_Message_`` doesn't exist (anymore). + + The solutions are either to use the memory spool or to load the + ``swiftmailer`` service without the ``lazy`` option (see :doc:`/service_container/lazy_services`). + +How to Test that an Email is Sent in a Functional Test +------------------------------------------------------ + +Sending emails with Symfony is pretty straightforward thanks to the +SwiftmailerBundle, which leverages the power of the `Swift Mailer`_ library. + +To functionally test that an email was sent, and even assert the email subject, +content or any other headers, you can use :doc:`the Symfony Profiler `. + +Start with a controller action that sends an email:: + + public function sendEmail($name, \Swift_Mailer $mailer) + { + $message = (new \Swift_Message('Hello Email')) + ->setFrom('send@example.com') + ->setTo('recipient@example.com') + ->setBody('You should see me from the profiler!') + ; + + $mailer->send($message); + + // ... + } + +In your functional test, use the ``swiftmailer`` collector on the profiler +to get information about the messages sent on the previous request:: + + // tests/Controller/MailControllerTest.php + namespace App\Tests\Controller; + + use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + + class MailControllerTest extends WebTestCase + { + public function testMailIsSentAndContentIsOk() + { + $client = static::createClient(); + + // enables the profiler for the next request (it does nothing if the profiler is not available) + $client->enableProfiler(); + + $crawler = $client->request('POST', '/path/to/above/action'); + + $mailCollector = $client->getProfile()->getCollector('swiftmailer'); + + // checks that an email was sent + $this->assertSame(1, $mailCollector->getMessageCount()); + + $collectedMessages = $mailCollector->getMessages(); + $message = $collectedMessages[0]; + + // Asserting email data + $this->assertInstanceOf('Swift_Message', $message); + $this->assertSame('Hello Email', $message->getSubject()); + $this->assertSame('send@example.com', key($message->getFrom())); + $this->assertSame('recipient@example.com', key($message->getTo())); + $this->assertSame( + 'You should see me from the profiler!', + $message->getBody() + ); + } + } + +Troubleshooting +~~~~~~~~~~~~~~~ + +Problem: The Collector Object Is ``null`` +......................................... + +The email collector is only available when the profiler is enabled and collects +information, as explained in :doc:`/testing/profiling`. -.. toctree:: - :maxdepth: 1 +Problem: The Collector Doesn't Contain the Email +................................................ - email/dev_environment - email/spool - email/testing +If a redirection is performed after sending the email (for example when you send +an email after a form is processed and before redirecting to another page), make +sure that the test client doesn't follow the redirects, as explained in +:doc:`/testing`. Otherwise, the collector will contain the information of the +redirected page and the email won't be accessible. +.. _`MailCatcher`: https://github.com/sj26/mailcatcher +.. _`MailHog`: https://github.com/mailhog/MailHog .. _`Swift Mailer`: http://swiftmailer.org/ .. _`SwiftMailerBundle`: https://github.com/symfony/swiftmailer-bundle .. _`Creating Messages`: https://swiftmailer.symfony.com/docs/messages.html diff --git a/email/dev_environment.rst b/email/dev_environment.rst deleted file mode 100644 index 2116618a7d0..00000000000 --- a/email/dev_environment.rst +++ /dev/null @@ -1,252 +0,0 @@ -.. index:: - single: Emails; In development - -How to Work with Emails during Development -========================================== - -When developing an application which sends email, you will often -not want to actually send the email to the specified recipient during -development. If you are using the SwiftmailerBundle with Symfony, you -can achieve this through configuration settings without having to make -any changes to your application's code at all. There are two main choices -when it comes to handling email during development: (a) disabling the -sending of email altogether or (b) sending all email to a specific -address (with optional exceptions). - -Disabling Sending ------------------ - -You can disable sending email by setting the ``disable_delivery`` option to -``true``, which is the default value used by Symfony in the ``test`` environment -(email messages will continue to be sent in the other environments): - -.. 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", - ]); - -.. _sending-to-a-specified-address: - -Sending to a Specified Address(es) ----------------------------------- - -You can also choose to have all email sent to a specific address or a list of addresses, instead -of the address actually specified when sending the message. This can be done -via the ``delivery_addresses`` option: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/dev/swiftmailer.yaml - swiftmailer: - delivery_addresses: ['dev@example.com'] - - .. code-block:: xml - - - - - - - dev@example.com - - - - .. code-block:: php - - // config/packages/dev/swiftmailer.php - $container->loadFromExtension('swiftmailer', [ - 'delivery_addresses' => ['dev@example.com'], - ]); - -Now, suppose you're sending an email to ``recipient@example.com`` in a controller:: - - public function index($name, \Swift_Mailer $mailer) - { - $message = (new \Swift_Message('Hello Email')) - ->setFrom('send@example.com') - ->setTo('recipient@example.com') - ->setBody( - $this->renderView( - 'HelloBundle:Hello:email.txt.twig', - ['name' => $name] - ) - ) - ; - $mailer->send($message); - - return $this->render(...); - } - -In the ``dev`` environment, the email will instead be sent to ``dev@example.com``. -Swift Mailer will add an extra header to the email, ``X-Swift-To``, containing -the replaced address, so you can still see who it would have been sent to. - -.. note:: - - In addition to the ``to`` addresses, this will also stop the email being - sent to any ``CC`` and ``BCC`` addresses set for it. Swift Mailer will add - additional headers to the email with the overridden addresses in them. - These are ``X-Swift-Cc`` and ``X-Swift-Bcc`` for the ``CC`` and ``BCC`` - addresses respectively. - -.. _sending-to-a-specified-address-but-with-exceptions: - -Sending to a Specified Address but with Exceptions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Suppose you want to have all email redirected to a specific address, -(like in the above scenario to ``dev@example.com``). But then you may want -email sent to some specific email addresses to go through after all, and -not be redirected (even if it is in the dev environment). This can be done -by adding the ``delivery_whitelist`` option: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/dev/swiftmailer.yaml - swiftmailer: - delivery_addresses: ['dev@example.com'] - delivery_whitelist: - # all email addresses matching these regexes will be delivered - # like normal, as well as being sent to dev@example.com - - '/@specialdomain\.com$/' - - '/^admin@mydomain\.com$/' - - .. code-block:: xml - - - - - - - - /@specialdomain\.com$/ - /^admin@mydomain\.com$/ - dev@example.com - - - - .. code-block:: php - - // config/packages/dev/swiftmailer.php - $container->loadFromExtension('swiftmailer', [ - 'delivery_addresses' => ["dev@example.com"], - 'delivery_whitelist' => [ - // all email addresses matching these regexes will be delivered - // like normal, as well as being sent to dev@example.com - '/@specialdomain\.com$/', - '/^admin@mydomain\.com$/', - ], - ]); - -In the above example all email messages will be redirected to ``dev@example.com`` -and messages sent to the ``admin@mydomain.com`` address or to any email address -belonging to the domain ``specialdomain.com`` will also be delivered as normal. - -.. caution:: - - The ``delivery_whitelist`` option is ignored unless the ``delivery_addresses`` option is defined. - -Viewing from the Web Debug Toolbar ----------------------------------- - -You can view any email sent during a single response when you are in the -``dev`` environment using the web debug toolbar. The email icon in the toolbar -will show how many emails were sent. If you click it, a report will open -showing the details of the sent emails. - -If you're sending an email and then immediately redirecting to another page, -the web debug toolbar will not display an email icon or a report on the next -page. - -Instead, you can set the ``intercept_redirects`` option to ``true`` in the -``dev`` environment, which will cause the redirect to stop and allow you to open -the report with details of the sent emails. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/dev/web_profiler.yaml - web_profiler: - intercept_redirects: true - - .. code-block:: xml - - - - - - - - - .. code-block:: php - - // config/packages/dev/web_profiler.php - $container->loadFromExtension('web_profiler', [ - 'intercept_redirects' => 'true', - ]); - -.. tip:: - - Alternatively, you can open the profiler after the redirect and search - by the submit URL used on the previous request (e.g. ``/contact/handle``). - The profiler's search feature allows you to load the profiler information - for any past requests. - -.. tip:: - - In addition to the features provided by Symfony, there are applications that - can help you test emails during application development, like `MailCatcher`_ - and `MailHog`_. - -.. _`MailCatcher`: https://github.com/sj26/mailcatcher -.. _`MailHog`: https://github.com/mailhog/MailHog diff --git a/email/spool.rst b/email/spool.rst deleted file mode 100644 index 47d96c00cf4..00000000000 --- a/email/spool.rst +++ /dev/null @@ -1,164 +0,0 @@ -.. index:: - single: Emails; Spooling - -How to Spool Emails -=================== - -The default behavior of the Symfony mailer is to send the email messages -immediately. You may, however, want to avoid the performance hit of the -communication to the email server, which could cause the user to wait for the -next page to load while the email is sending. This can be avoided by choosing to -"spool" the emails instead of sending them directly. - -This makes the mailer to not attempt to send the email message but instead save -it somewhere such as a file. Another process can then read from the spool and -take care of sending the emails in the spool. Currently only spooling to file or -memory is supported. - -.. _email-spool-memory: - -Spool Using Memory ------------------- - -When you use spooling to store the emails to memory, they will get sent right -before the kernel terminates. This means the email only gets sent if the whole -request got executed without any unhandled exception or any errors. To configure -this spool, use the following configuration: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/swiftmailer.yaml - swiftmailer: - # ... - spool: { type: memory } - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - // config/packages/swiftmailer.php - $container->loadFromExtension('swiftmailer', [ - // ... - 'spool' => ['type' => 'memory'], - ]); - -.. _spool-using-a-file: - -Spool Using Files ------------------- - -When you use the filesystem for spooling, Symfony creates a folder in the given -path for each mail service (e.g. "default" for the default service). This folder -will contain files for each email in the spool. So make sure this directory is -writable by Symfony (or your webserver/php)! - -In order to use the spool with files, use the following configuration: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/swiftmailer.yaml - swiftmailer: - # ... - spool: - type: file - path: /path/to/spooldir - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - // config/packages/swiftmailer.php - $container->loadFromExtension('swiftmailer', [ - // ... - - 'spool' => [ - 'type' => 'file', - 'path' => '/path/to/spooldir', - ], - ]); - -.. tip:: - - If you want to store the spool somewhere with your project directory, - remember that you can use the ``%kernel.project_dir%`` parameter to reference - the project's root: - - .. code-block:: yaml - - path: '%kernel.project_dir%/var/spool' - -Now, when your app sends an email, it will not actually be sent but instead -added to the spool. Sending the messages from the spool is done separately. -There is a console command to send the messages in the spool: - -.. code-block:: terminal - - $ APP_ENV=prod php bin/console swiftmailer:spool:send - -It has an option to limit the number of messages to be sent: - -.. code-block:: terminal - - $ APP_ENV=prod php bin/console swiftmailer:spool:send --message-limit=10 - -You can also set the time limit in seconds: - -.. code-block:: terminal - - $ APP_ENV=prod php bin/console swiftmailer:spool:send --time-limit=10 - -In practice you will not want to run this manually. Instead, the console command -should be triggered by a cron job or scheduled task and run at a regular -interval. - -.. caution:: - - When you create a message with SwiftMailer, it generates a ``Swift_Message`` - class. If the ``swiftmailer`` service is lazy loaded, it generates instead a - proxy class named ``Swift_Message_``. - - If you use the memory spool, this change is transparent and has no impact. - But when using the filesystem spool, the message class is serialized in - a file with the randomized class name. The problem is that this random - class name changes on every cache clear. So if you send a mail and then you - clear the cache, the message will not be unserializable. - - On the next execution of ``swiftmailer:spool:send`` an error will raise because - the class ``Swift_Message_`` doesn't exist (anymore). - - The solutions are either to use the memory spool or to load the - ``swiftmailer`` service without the ``lazy`` option (see :doc:`/service_container/lazy_services`). diff --git a/email/testing.rst b/email/testing.rst deleted file mode 100644 index 8ca65047d9e..00000000000 --- a/email/testing.rst +++ /dev/null @@ -1,85 +0,0 @@ -.. index:: - single: Emails; Testing - -How to Test that an Email is Sent in a Functional Test -====================================================== - -Sending emails with Symfony is pretty straightforward thanks to the -SwiftmailerBundle, which leverages the power of the `Swift Mailer`_ library. - -To functionally test that an email was sent, and even assert the email subject, -content or any other headers, you can use :doc:`the Symfony Profiler `. - -Start with a controller action that sends an email:: - - public function sendEmail($name, \Swift_Mailer $mailer) - { - $message = (new \Swift_Message('Hello Email')) - ->setFrom('send@example.com') - ->setTo('recipient@example.com') - ->setBody('You should see me from the profiler!') - ; - - $mailer->send($message); - - // ... - } - -In your functional test, use the ``swiftmailer`` collector on the profiler -to get information about the messages sent on the previous request:: - - // tests/Controller/MailControllerTest.php - namespace App\Tests\Controller; - - use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; - - class MailControllerTest extends WebTestCase - { - public function testMailIsSentAndContentIsOk() - { - $client = static::createClient(); - - // enables the profiler for the next request (it does nothing if the profiler is not available) - $client->enableProfiler(); - - $crawler = $client->request('POST', '/path/to/above/action'); - - $mailCollector = $client->getProfile()->getCollector('swiftmailer'); - - // checks that an email was sent - $this->assertSame(1, $mailCollector->getMessageCount()); - - $collectedMessages = $mailCollector->getMessages(); - $message = $collectedMessages[0]; - - // Asserting email data - $this->assertInstanceOf('Swift_Message', $message); - $this->assertSame('Hello Email', $message->getSubject()); - $this->assertSame('send@example.com', key($message->getFrom())); - $this->assertSame('recipient@example.com', key($message->getTo())); - $this->assertSame( - 'You should see me from the profiler!', - $message->getBody() - ); - } - } - -Troubleshooting ---------------- - -Problem: The Collector Object Is ``null`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The email collector is only available when the profiler is enabled and collects -information, as explained in :doc:`/testing/profiling`. - -Problem: The Collector Doesn't Contain the Email -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If a redirection is performed after sending the email (for example when you send -an email after a form is processed and before redirecting to another page), make -sure that the test client doesn't follow the redirects, as explained in -:doc:`/testing`. Otherwise, the collector will contain the information of the -redirected page and the email won't be accessible. - -.. _`Swift Mailer`: http://swiftmailer.org/ diff --git a/index.rst b/index.rst index df3e3ac12e7..be3dd71ae07 100644 --- a/index.rst +++ b/index.rst @@ -42,6 +42,7 @@ Topics frontend http_cache logging + mailer mercure messenger performance diff --git a/mailer.rst b/mailer.rst new file mode 100644 index 00000000000..5e5534496cd --- /dev/null +++ b/mailer.rst @@ -0,0 +1,649 @@ +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 +------------ + +.. caution:: + + The Mailer component is experimental in Symfony 4.3: some backwards compatibility + breaks could occur before 4.4. + +Symfony's Mailer & :doc:`Mime ` components form a *powerful* system +for creating and sending emails - complete with support for multipart messages, Twig +integration, CSS inlining, file attachments and a lot more. Get them installed with: + +.. code-block:: terminal + + $ composer require symfony/mailer + +Transport Setup +--------------- + +Emails are delivered via a "transport". And without installing anything else, you +can deliver emails over ``smtp`` by configuring your ``.env`` file: + +.. code-block:: bash + + # .env + MAILER_DSN=smtp://user:pass@smtp.example.com + +Using a 3rd Party Transport +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +But an easier option is to send emails via a 3rd party provider. Mailer supports +several - install whichever you want: + +================== ============================================= +Service Install with +================== ============================================= +Amazon SES ``composer require symfony/amazon-mailer`` +MailChimp ``composer require symfony/mailchimp-mailer`` +Mailgun ``composer require symfony/mailgun-mailer`` +Postmark ``composer require symfony/postmark-mailer`` +SendGrid ``composer require symfony/sendgrid-mailer`` +Gmail ``composer require symfony/google-mailer`` +================== ============================================= + +Each library includes a :ref:`Flex recipe ` that will add example configuration +to your ``.env`` file. For example, suppose you want to use SendGrid. First, +install it: + +.. code-block:: terminal + + $ composer require symfony/sendgrid-mailer + +You'll now have a new line in your ``.env`` file that you can uncomment: + +.. code-block:: bash + + # .env` + + SENDGRID_KEY= + MAILER_DSN=smtp://$SENDGRID_KEY@sendgrid + +The``MAILER_DSN`` isn't a *real* SMTP address: it's a simple format that offloads +most of the configuration work to mailer. The ``@sendgrid`` part of the address +activates the SendGrid mailer library that you just installed, which knows all +about how to deliver messages to SendGrid. + +The *only* part you need to change is to set ``SENDGRID_KEY`` to your key (in +``.env`` or ``.env.local``). + +Each transport will have different environment variables that the library will use +to configure the *actual* address and authentication for delivery. Some also have +options that can be configured with query parameters on end of the ``MAILER_DSN`` - +like ``?region=`` for Amazon SES. Some transports support sending via ``http`` +or ``smtp`` - both work the same, but ``http`` is recommended when available. + +Creating & Sending Messages +--------------------------- + +To send an email, autowire the mailer using +:class:`Symfony\\Component\\Mailer\\MailerInterface` (service id ``mailer``) +and create an :class:`Symfony\\Component\\Mime\\Email` object:: + + // src/Controller/MailerController.php + namespace App\Controller; + + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + use Symfony\Component\Mailer\MailerInterface; + use Symfony\Component\Mime\Email; + + class MailerController extends AbstractController + { + /** + * @Route("/email") + */ + public function sendEmail(MailerInterface $mailer) + { + $email = (new Email()) + ->from('hello@example.com') + ->to('you@example.com') + //->cc('cc@example.com') + //->bcc('bcc@example.com') + //->replyTo('fabien@example.com') + //->priority(Email::PRIORITY_HIGH) + ->subject('Time for Symfony Mailer!') + ->text('Sending emails is fun again!') + ->html('

See Twig integration for better HTML integration!

'); + + $mailer->send($email); + + // ... + } + } + +That's it! The message will be sent via whatever transport you configured. + +Email Addresses +~~~~~~~~~~~~~~~ + +All the methods that require email addresses (``from()``, ``to()``, etc.) accept +both strings or address objects:: + + // ... + use Symfony\Component\Mime\Address; + use Symfony\Component\Mime\NamedAddress; + + $email = (new Email()) + // email address as a simple string + ->from('fabien@example.com') + + // email address as an object + ->from(new Address('fabien@example.com')) + + // email address as an object (email clients will display the name + // instead of the email address) + ->from(new NamedAddress('fabien@example.com', 'Fabien')) + + // ... + ; + +Multiple addresses are defined with the ``addXXX()`` methods:: + + $email = (new Email()) + ->to('foo@example.com') + ->addTo('bar@example.com') + ->addTo('baz@example.com') + + // ... + ; + +Alternatively, you can pass multiple addresses to each method:: + + $toAddresses = ['foo@example.com', new Address('bar@example.com')]; + + $email = (new Email()) + ->to(...$toAddresses) + ->cc('cc1@example.com', 'cc2@example.com') + + // ... + ; + +Message Contents +~~~~~~~~~~~~~~~~ + +The text and HTML contents of the email messages can be strings (usually the +result of rendering some template) or PHP resources:: + + $email = (new Email()) + // ... + // simple contents defined as a string + ->text('Lorem ipsum...') + ->html('

Lorem ipsum...

') + + // attach a file stream + ->text(fopen('/path/to/emails/user_signup.txt', 'r')) + ->html(fopen('/path/to/emails/user_signup.html', 'r')) + ; + +.. tip:: + + You can also use Twig templates to render the HTML and text contents. Read + the `Twig: HTML & CSS`_ section later in this article to + learn more. + +File Attachments +~~~~~~~~~~~~~~~~ + +Use the ``attachFromPath()`` method to attach files that exist on your file system:: + + $email = (new Email()) + // ... + ->attachFromPath('/path/to/documents/terms-of-use.pdf') + // optionally you can tell email clients to display a custom name for the file + ->attachFromPath('/path/to/documents/privacy.pdf', 'Privacy Policy') + // optionally you can provide an explicit MIME type (otherwise it's guessed) + ->attachFromPath('/path/to/documents/contract.doc', 'Contract', 'application/msword') + ; + +Alternatively you can use the ``attach()`` method to attach contents from a stream:: + + $email = (new Email()) + // ... + ->attach(fopen('/path/to/documents/contract.doc', 'r')) + ; + +Embedding Images +~~~~~~~~~~~~~~~~ + +If you want to display images inside your email, you must embed them +instead of adding them as attachments. When using Twig to render the email +contents, as explained `later in this article `_, +the images are embedded automatically. Otherwise, you need to embed them manually. + +First, use the ``embed()`` or ``embedFromPath()`` method to add an image from a +file or stream:: + + $email = (new Email()) + // ... + // get the image contents from a PHP resource + ->embed(fopen('/path/to/images/logo.png', 'r'), 'logo') + // get the image contents from an existing file + ->embedFromPath('/path/to/images/signature.gif', 'footer-signature') + ; + +The second optional argument of both methods is the image name ("Content-ID" in +the MIME standard). Its value is an arbitrary string used later to reference the +images inside the HTML contents:: + + $email = (new Email()) + // ... + ->embed(fopen('/path/to/images/logo.png', 'r'), 'logo') + ->embedFromPath('/path/to/images/signature.gif', 'footer-signature') + // reference images using the syntax 'cid:' + "image embed name" + ->html(' ... ...') + ; + +Global from Address +------------------- + +Instead of calling ``->from()`` *every* time you create a new email, you can +create an event subscriber to set it automatically:: + + // src/EventListener/MailerFromListener.php + namespace App\EventListener; + + use Symfony\Component\EventDispatcher\EventSubscriberInterface; + use Symfony\Component\Mailer\Event\MessageEvent; + use Symfony\Component\Mime\Email; + + class MailerFromListener implements EventSubscriberInterface + { + public function onMessageSend(MessageEvent $event) + { + $message = $event->getMessage(); + + // make sure it's an Email object + if (!$message instanceof Email) { + return; + } + + // always set the from address + $message->from('fabien@example.com'); + } + + public static function getSubscribedEvents() + { + return [MessageEvent::class => 'onMessageSend']; + } + } + +.. _mailer-twig: + +Twig: HTML & CSS +---------------- + +The Mime component integrates with the :doc:`Twig template engine ` +to provide advanced features such as CSS style inlining and support for HTML/CSS +frameworks to create complex HTML email messages. First, make sure Twig is instaled: + +.. code-block:: terminal + + $ composer require symfony/twig-bundle + +HTML Content +~~~~~~~~~~~~ + +To define the contents of your email with Twig, use the +:class:`Symfony\\Bridge\\Twig\\Mime\\TemplatedEmail` class. This class extends +the normal :class:`Symfony\\Component\\Mime\\Email` class but adds some new methods +for Twig templates:: + + use Symfony\Bridge\Twig\Mime\TemplatedEmail; + + $email = (new TemplatedEmail()) + ->from('fabien@example.com') + ->to(new NamedAddress('ryan@example.com', 'Ryan')) + ->subject('Thanks for signing up!') + + // path of the Twig template to render + ->htmlTemplate('emails/signup.html.twig') + + // pass variables (name => value) to the template + ->context([ + 'expiration_date' => new \DateTime('+7 days'), + 'username' => 'foo', + ]) + ; + +Then, create the template: + +.. code-block:: html+twig + + {# templates/emails/signup.html.twig #} +

Welcome {{ email.toName }}!

+ +

+ You signed up as {{ username }} the following email: +

+

{{ email.to[0].address }}

+ +

+ Click here to activate your account + (this link is valid until {{ expiration_date|date('F jS') }}) +

+ +The Twig template has access to any of the parameters passed in the ``context()`` +method of the ``TemplatedEmail`` class and also to a special variable called +``email``, which is an instance of +:class:`Symfony\\Bridge\\Twig\\Mime\\WrappedTemplatedEmail`. + +Text Content +~~~~~~~~~~~~ + +When the text content of a ``TemplatedEmail`` is not explicitly defined, mailer +will generate it automatically by converting the HTML contents into text. If you +have `league/html-to-markdown`_ installed in your application, +it uses that to turn HTML into Markdown (so the text email has some visual appeal). +Otherwise, it applies the :phpfunction:`strip_tags` PHP function to the original +HTML contents. + +If you want to define the text content yourself, use the ``text()`` method +explained in the previous sections or the ``textTemplate()`` method provided by +the ``TemplatedEmail`` class: + +.. code-block:: diff + + + use Symfony\Bridge\Twig\Mime\TemplatedEmail; + + $email = (new TemplatedEmail()) + // ... + + ->htmlTemplate('emails/signup.html.twig') + + ->textTemplate('emails/signup.txt.twig') + // ... + ; + +Embedding Images +~~~~~~~~~~~~~~~~ + +Instead of dealing with the ```` syntax explained in the +previous sections, when using Twig to render email contents you can refer to +image files as usual. First, to simplify things, define a Twig namespace called +``images`` that points to whatever directory your images are stored in: + +.. code-block:: yaml + + # config/packages/twig.yaml + twig: + # ... + + paths: + # point this wherever your images live + images: '%kernel.project_dir%/assets/images' + +Now, use the special ``email.image()`` Twig helper to embed the images inside +the email contents: + +.. code-block:: html+twig + + {# '@images/' refers to the Twig namespace defined earlier #} + Logo + +

Welcome {{ email.toName }}!

+ {# ... #} + +.. _mailer-inline-css: + +Inlining CSS Styles +~~~~~~~~~~~~~~~~~~~ + +Designing the HTML contents of an email is very different from designing a +normal HTML page. For starters, most email clients only support a subset of all +CSS features. In addition, popular email clients like Gmail don't support +defining styles inside ```` sections and you must **inline +all the CSS styles**. + +CSS inlining means that every HTML tag must define a ``style`` attribute with +all its CSS styles. This can make organizing your CSS a mess. That's why Twig +provides a ``CssInlinerExtension`` that automates everything for you. Install +it with: + +.. code-block:: terminal + + $ composer require twig/cssinliner-extension + +The extension is enabled automatically. To use this, wrap the entire template +with the ``inline_css`` filter: + +.. code-block:: html+twig + + {% filter inline_css %} + + +

Welcome {{ email.toName }}!

+ {# ... #} + {% endfilter %} + +Using External CSS Files +........................ + +You can also define CSS styles in external files and pass them as +arguments to the filter: + +.. code-block:: html+twig + + {% filter inline_css(source('@css/email.css')) %} +

Welcome {{ username }}!

+ {# ... #} + {% endfilter %} + +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: + +.. _mailer-css-namespace: + +.. code-block:: yaml + + # config/packages/twig.yaml + twig: + # ... + + paths: + # point this wherever your css files live + css: '%kernel.project_dir%/assets/css' + +.. _mailer-markdown: + +Rendering Markdown Content +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Twig provides another extension called ``MarkdownExtension`` that lets you +define the email contents using `Markdown syntax`_. To use this, install the +extension and a Markdown conversion library (the extension is compatible with +several popular libraries): + +.. code-block:: terminal + + # instead of league/commonmark, you can also use erusev/parsedown or michelf/php-markdown + $ composer require twig/markdown-extension league/commonmark + +The extension adds a ``markdown`` filter, which you can use to convert parts or +the entire email contents from Markdown to HTML: + +.. code-block:: twig + + {% filter markdown %} + Welcome {{ email.toName }}! + =========================== + + You signed up to our site using the following email: + `{{ email.to[0].address }}` + + [Click here to activate your account]({{ url('...') }}) + {% endfilter %} + +.. _mailer-inky: + +Inky Email Templating Language +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Creating beautifully designed emails that work on every email client is so +complex that there are HTML/CSS frameworks dedicated to that. One of the most +popular frameworks is called `Inky`_. It defines a syntax based on some simple +tags which are later transformed into the real HTML code sent to users: + +.. code-block:: html + + + + + This is a column. + + + +Twig provides integration with Inky via the ``InkyExtension``. First, install +the extension in your application: + +.. code-block:: terminal + + $ composer require twig/inky-extension + +The extension adds an ``inky`` filter, which can be used to convert parts or the +entire email contents from Inky to HTML: + +.. code-block:: html+twig + + {% filter inky %} + + + + +

Welcome {{ email.toName }}!

+
+ + {# ... #} +
+
+ {% endfilter %} + +You can combine all filters to create complex email messages: + +.. code-block:: twig + + {% filter inky|inline_css(source('@css/foundation-emails.css')) %} + {# ... #} + {% endfilter %} + +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``. + +Sending Messages Async +---------------------- + +When you call ``$mailer->send($email)``, the email is sent to the transport immediately. +To improve performance, you can leverage :doc:`Messenger ` to send +the messages later via a Messenger transport. + +Start by following the :doc:`Messenger ` documentation and configuring +a transport. Once everything is set up, when you call ``$mailer->send()``, a +:class:`Symfony\\Component\\Mailer\\Messenger\\SendEmailMessage` message will +be dispatched through the default message bus (``messenger.default_bus``). Assuming +you have a transport called ``async``, you can route the message there: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/messenger.yaml + framework: + messenger: + transports: + async: "%env(MESSENGER_TRANSPORT_DSN)%" + + routing: + 'Symfony\Component\Mailer\Messenger\SendEmailMessage': async + + .. code-block:: xml + + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/messenger.php + $container->loadFromExtension('framework', [ + 'messenger' => [ + 'routing' => [ + 'Symfony\Component\Mailer\Messenger\SendEmailMessage' => 'async', + ], + ], + ]); + +Thanks to this, instead of being delivered immediately, messages will be sent to +the transport to be handled later (see :ref:`messenger-worker`). + +Development & Debugging +----------------------- + +Disabling Delivery +~~~~~~~~~~~~~~~~~~ + +While developing (or testing), you may want to disable delivery of messages entirely. +You can do this by forcing Mailer to use the ``NullTransport`` in only the ``dev`` +environment: + +.. code-block:: yaml + + # config/packages/dev/mailer.yaml + framework: + mailer: + dsn: 'smtp://null' + +.. note:: + + If you're using Messenger and routing to a transport, the message will *still* + be sent to that transport. + +Always Send to the Same Address +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Instead of disabling delivery entirely, you might want to *always* send emails to +a specific address, instead of the *real* address. To do that, you can take +advantage of the ``EnvelopeListener`` and register it *only* for the ``dev`` +environment: + +.. code-block:: yaml + + # config/services_dev.yaml + services: + mailer.dev.set_recipients: + class: Symfony\Component\Mailer\EventListener\EnvelopeListener + tags: ['kernel.event_subscriber'] + arguments: + $sender: null + $recipients: ['youremail@example.com'] + +.. _`download the foundation-emails.css file`: https://github.com/zurb/foundation-emails/blob/develop/dist/foundation-emails.css +.. _`league/html-to-markdown`: https://github.com/thephpleague/html-to-markdown +.. _`Markdown syntax`: https://commonmark.org/ +.. _`Inky`: https://foundation.zurb.com/emails.html diff --git a/reference/configuration/swiftmailer.rst b/reference/configuration/swiftmailer.rst index d53935b8d59..8a6a2cd77e8 100644 --- a/reference/configuration/swiftmailer.rst +++ b/reference/configuration/swiftmailer.rst @@ -157,7 +157,7 @@ values are ``plain``, ``login``, ``cram-md5``, or ``null``. spool ~~~~~ -For details on email spooling, see :doc:`/email/spool`. +For details on email spooling, see :doc:`/mailer`. type .... diff --git a/setup/flex.rst b/setup/flex.rst index 055cd30d015..328f13a098b 100644 --- a/setup/flex.rst +++ b/setup/flex.rst @@ -51,6 +51,8 @@ SwiftmailerBundle and returns the "recipe" for it. Flex keeps tracks of the recipes it installed in a ``symfony.lock`` file, which must be committed to your code repository. +.. _flex-recipe: + Symfony Flex Recipes ~~~~~~~~~~~~~~~~~~~~ From 3fc6102519e3e6b5cb59ddf70180a6c40c06cff1 Mon Sep 17 00:00:00 2001 From: Victor Bocharsky Date: Sat, 1 Jun 2019 00:58:55 +0300 Subject: [PATCH 190/499] Fix a few minor misprints in Mailer article --- mailer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mailer.rst b/mailer.rst index 5e5534496cd..f802628db23 100644 --- a/mailer.rst +++ b/mailer.rst @@ -61,12 +61,12 @@ You'll now have a new line in your ``.env`` file that you can uncomment: .. code-block:: bash - # .env` + # .env SENDGRID_KEY= MAILER_DSN=smtp://$SENDGRID_KEY@sendgrid -The``MAILER_DSN`` isn't a *real* SMTP address: it's a simple format that offloads +The ``MAILER_DSN`` isn't a *real* SMTP address: it's a simple format that offloads most of the configuration work to mailer. The ``@sendgrid`` part of the address activates the SendGrid mailer library that you just installed, which knows all about how to deliver messages to SendGrid. From 5d561fb842f055bcafa63e2c3b7aea5fafcd9440 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Fri, 31 May 2019 15:23:54 -0400 Subject: [PATCH 191/499] tweaks to messenger docs based on feedback from @Tobion --- messenger.rst | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/messenger.rst b/messenger.rst index 91f3b4ac9ff..b7a5f2ffbd6 100644 --- a/messenger.rst +++ b/messenger.rst @@ -368,7 +368,7 @@ Handling Messages Synchronously If a message doesn't :ref:`match any routing rules `, it won't be sent to any transport and will be handled immediately. In some cases (like -when :ref:`sending handlers to different transports`), +when `binding handlers to different transports`_), it's easier or more flexible to handle this explicitly: by creating a ``sync`` transport and "sending" messages there to be handled immediately: @@ -709,7 +709,11 @@ to retry them: $ php bin/console messenger:failed:retry 20 30 --force # remove a message without retrying it - $ php bin/console messenger:failed:retry 20 + $ php bin/console messenger:failed:remove 20 + +If the messages fails again, it will be re-sent back to the failure transport +due to the normal `retry rules `_. Once the max retry has +been hit, the message will be discarded permanently. .. _messenger-transports-config: @@ -773,12 +777,17 @@ a table named ``messenger_messages`` (this is configurable) when the transport i first used. You can disable that with the ``auto_setup`` option and set the table up manually by calling the ``messenger:setup-transports`` command. -.. caution:: +.. tip:: + + To avoid tools like Doctrine Migrations from trying to remove this table because + it's not part of your normal schema, you can set the ``schema_filter`` option: - If you use Doctrine Migrations, each generated migration will try to drop - the ``messenger_messages`` table and needs to be removed manually. You - cannot (yet) use ``doctrine.dbal.schema_filter`` to avoid. See - https://github.com/symfony/symfony/issues/31623. + .. code-block:: yaml + + # config/packages/doctrine.yaml + doctrine: + dbal: + schema_filter: '~^(?!messenger_messages)~' The transport has a number of options: @@ -842,14 +851,14 @@ Options defined under ``options`` take precedence over ones defined in the DSN. ================== =================================== ======= table_name Name of the table messenger_messages queue_name Name of the queue (a column in the default - table, to use-use one table for + table, to use one table for multiple transports) redeliver_timeout Timeout before retrying a messages 3600 that's in the queue but in the "handling" state (if a worker died for some reason, this will occur, eventually you should retry the - message) + message) - in seconds. auto_setup Whether the table should be created automatically during send / get. true ================== =================================== ======= @@ -875,7 +884,7 @@ a running Redis server (^5.0). The Redis transport does not support "delayed" messages. -A number of options can be configured via the DSN of 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``: ================== =================================== ======= @@ -1065,9 +1074,7 @@ A handler class can handle multiple messages or configure itself by implementing } } -.. _messenger-handlers-different-transports: - -Sending Handlers to Different Transports +Binding Handlers to Different Transports ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Each message can have multiple handlers, and when a message is consumed @@ -1239,17 +1246,18 @@ collection of middleware (and their order). By default, the middleware configure for each bus looks like this: #. ``add_bus_name_stamp_middleware`` - adds a stamp to record which bus this - message was dispatched into. + message was dispatched into; -#. ``dispatch_after_current_bus``- see :doc:`/messenger/message-recorder`. +#. ``dispatch_after_current_bus``- see :doc:`/messenger/message-recorder`; -#. ``failed_message_processing_middleware`` - sends failed messages to the - :ref:`failure transport `. +#. ``failed_message_processing_middleware`` - processes messages that are being + retried via the :ref:`failure transport ` to make + them properly function as if they were being received from their original transport; #. Your own collection of middleware_; #. ``send_message`` - if routing is configured for the transport, this sends - messages to that transport and stops the middleware chain. + messages to that transport and stops the middleware chain; #. ``handle_message`` - calls the message handler(s) for the given message. From 44b2b6cc02f7469fdf787ddf3cf586da27c205c2 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sun, 2 Jun 2019 16:22:56 +0200 Subject: [PATCH 192/499] Fix several typos --- cache.rst | 2 +- components/var_dumper/advanced.rst | 2 +- components/workflow.rst | 2 +- configuration.rst | 2 +- configuration/dot-env-changes.rst | 2 +- mailer.rst | 2 +- reference/forms/types/hidden.rst | 2 +- testing/profiling.rst | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cache.rst b/cache.rst index b981fb148d4..3d4cbf96a3e 100644 --- a/cache.rst +++ b/cache.rst @@ -594,7 +594,7 @@ Clearing the Cache ------------------ To clear the cache you can use the ``bin/console cache:pool:clear [pool]`` command. -That will remove all the entries from your storage and you wil have to recalculate +That will remove all the entries from your storage and you will have to recalculate all values. You can also group your pools into "cache clearers". There are 3 cache clearers by default: diff --git a/components/var_dumper/advanced.rst b/components/var_dumper/advanced.rst index bdc388cd6fe..dd31f8fed95 100644 --- a/components/var_dumper/advanced.rst +++ b/components/var_dumper/advanced.rst @@ -188,7 +188,7 @@ method to use a light theme:: The :class:`Symfony\\Component\\VarDumper\\Dumper\\HtmlDumper` limits string length and nesting depth of the output to make it more readable. These options -can be overriden by the third optional parameter of the +can be overridden by the third optional parameter of the :method:`dump(Data $data) ` method:: diff --git a/components/workflow.rst b/components/workflow.rst index 3d3ac24cc2c..54db794696a 100644 --- a/components/workflow.rst +++ b/components/workflow.rst @@ -77,7 +77,7 @@ Usage ----- When you have configured a ``Registry`` with your workflows, -you can retreive a workflow from it and use it as follows:: +you can retrieve a workflow from it and use it as follows:: // ... // Consider that $post is in state "draft" by default diff --git a/configuration.rst b/configuration.rst index a875db604c1..9d968a5e8da 100644 --- a/configuration.rst +++ b/configuration.rst @@ -253,7 +253,7 @@ The ``.env`` file is special, because it defines the values that usually change on each server. For example, the database credentials on your local development machine might be different from your workmates. The ``.env`` file should contain sensible, non-secret *default* values for all of your environment variables and -*should* be commited to your repository. +*should* be committed to your repository. To override these variables with machine-specific or sensitive values, create a ``.env.local`` file. This file is **not committed to the shared repository** and diff --git a/configuration/dot-env-changes.rst b/configuration/dot-env-changes.rst index 1dff2d140d2..34377cf4b11 100644 --- a/configuration/dot-env-changes.rst +++ b/configuration/dot-env-changes.rst @@ -18,7 +18,7 @@ important changes: * A) The ``.env.dist`` file no longer exists. Its contents should be moved to your ``.env`` file (see the next point). -* B) The ``.env`` file **is** now commited to your repository. It was previously ignored +* B) The ``.env`` file **is** now committed to your repository. It was previously ignored via the ``.gitignore`` file (the updated recipe does not ignore this file). Because this file is committed, it should contain non-sensitive, default values. Basically, the ``.env.dist`` file was moved to ``.env``. diff --git a/mailer.rst b/mailer.rst index f802628db23..09de4e78ede 100644 --- a/mailer.rst +++ b/mailer.rst @@ -281,7 +281,7 @@ Twig: HTML & CSS The Mime component integrates with the :doc:`Twig template engine ` to provide advanced features such as CSS style inlining and support for HTML/CSS -frameworks to create complex HTML email messages. First, make sure Twig is instaled: +frameworks to create complex HTML email messages. First, make sure Twig is installed: .. code-block:: terminal diff --git a/reference/forms/types/hidden.rst b/reference/forms/types/hidden.rst index a5d5b6315ef..df3a370b7db 100644 --- a/reference/forms/types/hidden.rst +++ b/reference/forms/types/hidden.rst @@ -9,7 +9,7 @@ The hidden type represents a hidden input field. +-------------+----------------------------------------------------------------------+ | Rendered as | ``input`` ``hidden`` field | +-------------+----------------------------------------------------------------------+ -| Overriden | - `compound`_ | +| Overridden | - `compound`_ | | options | - `error_bubbling`_ | | | - `required`_ | +-------------+----------------------------------------------------------------------+ diff --git a/testing/profiling.rst b/testing/profiling.rst index 659a07c7573..bfe336442ec 100644 --- a/testing/profiling.rst +++ b/testing/profiling.rst @@ -105,7 +105,7 @@ provided by the collectors obtained through the ``$client->getProfile()`` call:: If a test fails because of profiling data (too many DB queries for instance), you might want to use the Web Profiler to analyze the request after the tests -finish. It can be achived by embedding the token in the error message:: +finish. It can be achieved by embedding the token in the error message:: $this->assertLessThan( 30, From 0f4f64effea4e991e1b532f9c9a6d5dcb3a72f60 Mon Sep 17 00:00:00 2001 From: Loulier Guillaume Date: Mon, 3 Jun 2019 08:30:52 +0200 Subject: [PATCH 193/499] fix(DI): service name --- components/http_client.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/http_client.rst b/components/http_client.rst index 55fe4f530df..9b05b30d677 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -483,11 +483,11 @@ has a unique service named after its configuration. # ... # whenever a service type-hints HttpClientInterface, inject the GitHub client - Symfony\Contracts\HttpClient\HttpClientInterface: '@api_client.github' + Symfony\Contracts\HttpClient\HttpClientInterface: '@some_api.client' # inject the HTTP client called 'crawler' into this argument of this service App\Some\Service: - $someArgument: '@http_client.crawler' + $someArgument: '@crawler.client' Testing HTTP Clients and Responses ---------------------------------- From ab6bb2cb4b68ae9eaf78f25a5f675628d7ebecb6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 3 Jun 2019 09:33:54 +0200 Subject: [PATCH 194/499] Typo --- messenger.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messenger.rst b/messenger.rst index b7a5f2ffbd6..f7ea60cf9ce 100644 --- a/messenger.rst +++ b/messenger.rst @@ -711,7 +711,7 @@ to retry them: # remove a message without retrying it $ php bin/console messenger:failed:remove 20 -If the messages fails again, it will be re-sent back to the failure transport +If the message fails again, it will be re-sent back to the failure transport due to the normal `retry rules `_. Once the max retry has been hit, the message will be discarded permanently. From 75786d878c0beaf4400c4cc27e2d65d8d0e7147b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 3 Jun 2019 16:27:26 +0200 Subject: [PATCH 195/499] [Mailer] Sort providers alphabetically --- mailer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index 09de4e78ede..01a69800cd9 100644 --- a/mailer.rst +++ b/mailer.rst @@ -42,11 +42,11 @@ 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`` Mailgun ``composer require symfony/mailgun-mailer`` Postmark ``composer require symfony/postmark-mailer`` SendGrid ``composer require symfony/sendgrid-mailer`` -Gmail ``composer require symfony/google-mailer`` ================== ============================================= Each library includes a :ref:`Flex recipe ` that will add example configuration From f9339a39498a4083bdaacf34b6c9bafcaa221a29 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 3 Jun 2019 16:01:29 +0200 Subject: [PATCH 196/499] [HttpClient] improve doc again --- components/http_client.rst | 216 ++++++++++++++++++++++++++++++------- 1 file changed, 177 insertions(+), 39 deletions(-) diff --git a/components/http_client.rst b/components/http_client.rst index 9b05b30d677..fff89f7b652 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -13,11 +13,6 @@ The HttpClient Component The HttpClient component was introduced in Symfony 4.3. -.. TODO -.. tell about implementation vs abstraction -.. tell there are more options -.. tell chunked + compression are supported out of the box - Installation ------------ @@ -71,17 +66,16 @@ 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. -Enabling HTTP/2 Support ------------------------ +HTTP/2 Support +-------------- -HTTP/2 is only supported when using the cURL-based transport and the libcurl -version is >= 7.36.0. If you meet these requirements, HTTP/2 will be used by -default when the request protocol is ``https``. If you need it for ``http``, -you must enable it explicitly via the ``http_version`` option:: +When requesting an ``https`` URL, HTTP/2 is enabled by default if libcurl >= 7.36 +is used. To force HTTP/2 for ``http`` URLs, you need to enable it explicitly via +the ``http_version`` option:: $httpClient = HttpClient::create(['http_version' => '2.0']); -Support for HTTP/2 PUSH works out of the box when libcurl >= 7.61.0 is used with +Support for HTTP/2 PUSH works out of the box when libcurl >= 7.61 is used with PHP >= 7.2.17 / 7.3.4: pushed responses are put into a temporary cache and are used when a subsequent request is triggered for the corresponding URLs. @@ -112,6 +106,11 @@ immediately instead of waiting to receive the response:: This component also supports :ref:`streaming responses ` for full asynchronous applications. +.. note:: + + HTTP compression and chunked transfer encoding are automatically enabled when + both your PHP runtime and the remote server support them. + Authentication ~~~~~~~~~~~~~~ @@ -233,13 +232,12 @@ making a request. Use the ``max_redirects`` setting to configure this behavior 'max_redirects' => 0, ]); -.. Concurrent Requests -.. ~~~~~~~~~~~~~~~~~~~ -.. -.. -.. TODO -.. -.. +Advanced Options +~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Contracts\\HttpClient\\HttpClientInterface` defines all the +options you might need to take full control of the way the request is performed, +including progress monitoring, DSN pre-resolution, timeout, SSL parameters, etc. Processing Responses -------------------- @@ -265,6 +263,12 @@ following methods:: // you can get individual info too $startTime = $response->getInfo('start_time'); +.. note:: + + ``$response->getInfo()`` is non-blocking: it returns *live* information + about the response. Some of them might not be know yet (e.g. ``http_code``) + when you'll call it. + .. tip:: Call ``$response->getInfo('debug')`` to get detailed logs about the HTTP transaction. @@ -317,6 +321,146 @@ When the HTTP status code of the response is in the 300-599 range (i.e. 3xx, // instead the original response content (even if it's an error message) $content = $response->getContent(false); +Concurrent Requests +------------------- + +Thanks to responses being lazy, requests are always managed concurrently. +On a fast enough network, the following code makes 379 requests in less than +half a second when cURL is used:: + + use Symfony\Component\HttpClient\CurlHttpClient; + + $client = new CurlHttpClient(); + + $responses = []; + + for ($i = 0; $i < 379; ++$i) { + $uri = "https://http2.akamai.com/demo/tile-$i.png"; + $responses[] = $client->request('GET', $uri); + } + + foreach ($responses as $response) { + $content = $response->getContent(); + // ... + } + +As you can read in the first "for" loop, requests are issued but are not consumed +yet. That's the trick when concurrency is desired: requests should be sent +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. + +Multiplexing Responses +~~~~~~~~~~~~~~~~~~~~~~ + +If you look again at the snippet above, responses are read in requests' order. +But maybe the 2nd response came back before the 1st? Fully asynchronous operations +require being able to deal with the responses in whatever order they come back. + +In order to do so, the ``stream()`` method of HTTP clients accepts a list of +responses to monitor. As mentionned :ref:`previously `, +this method yields response chunks as they arrive from the network. By replacing +the "foreach" in the snippet with this one, the code becomes fully async:: + + foreach ($client->stream($responses) as $response => $chunk) { + if ($chunk->isFirst()) { + // headers of $response just arrived + // $response->getHeaders() is now a non-blocking call + } elseif ($chunk->isLast()) { + // the full content of $response just completed + // $response->getContent() is now a non-blocking call + } else { + // $chunk->getContent() will return a piece + // of the response body that just arrived + } + } + +.. tip:: + + Use the ``user_data`` option combined with ``$response->getInfo('user_data')`` + to track the identity of the responses in your foreach loops. + +Dealing with Network Timeouts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This component allows dealing with both request and response timeouts. + +A timeout can happen when e.g. DNS resolution takes too much time, when the TCP +connection cannot be opened in the given time budget, or when the response +content pauses for too long. This can be configured with the ``timeout`` request +option:: + + // A TransportExceptionInterface will be issued if nothing + // happens for 2.5 seconds when accessing from the $response + $response = $client->request('GET', 'https://...', ['timeout' => 2.5]); + +The ``default_socket_timeout`` PHP ini setting is used if the option is not set. + +The option can be overriden by using the 2nd argument of the ``stream()`` method. +This allows monitoring several responses at once and applying the timeout to all +of them in a group. If all responses become inactive for the given duration, the +method will yield a special chunk whose ``isTimeout()`` will return ``true``:: + + foreach ($client->stream($responses, 1.5) as $response => $chunk) { + if ($chunk->isTimeout()) { + // $response staled for more than 1.5 seconds + } + } + +A timeout is not necessarily an error: you can decide to stream again the +response and get remaining contents that might come back in a new timeout, etc. + +.. tip:: + + Passing ``0`` as timeout allows monitoring responses in a non-blocking way. + +.. note:: + + Timeouts control how long one is willing to wait *while the HTTP transation + is idle*. Big responses can last as long as needed to complete, provided they + remain active during the transfer and never pause for longer than specified. + +Dealing with Network Errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Network errors (broken pipe, failed DSN resolution, etc.) are thrown as instances +of :class:`Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface`. + +First of all, you don't *have* to deal with them: letting errors bubble to your +generic exception-handling stack might be really fine in most use cases. + +If you want to handle them, here is what you need to know: + +To catch errors, you need to wrap calls to ``$client->request()`` but also calls +to any methods of the returned responses. This is because responses are lazy, so +that network errors can happen when calling e.g. ``getStatusCode()`` too:: + + try { + // both lines can potentially throw + $response = $client->request(...); + $headers = $response->getHeaders(); + // ... + } catch (TransportExceptionInterface $e) { + // ... + } + +.. note:: + + Because ``$response->getInfo()`` is non-blocking, it shouldn't throw by design. + +When multiplexing responses, you can deal with errors for individual streams by +catching ``TransportExceptionInterface`` in the foreach loop:: + + foreach ($client->stream($responses) as $response => $chunk) { + try { + if ($chunk->isLast()) { + // ... do something with $response + } + } catch (TransportExceptionInterface $e) { + // ... + } + } + Caching Requests and Responses ------------------------------ @@ -435,8 +579,9 @@ the available config options: framework: # ... http_client: - max_redirects: 7 max_host_connections: 10 + default_options: + max_redirects: 7 If you want to define multiple HTTP clients, use this other expanded configuration: @@ -448,16 +593,16 @@ If you want to define multiple HTTP clients, use this other expanded configurati http_client: scoped_clients: crawler.client: - headers: [{ 'X-Powered-By': 'ACME App' }] + headers: { 'X-Powered-By': 'ACME App' } http_version: '1.0' some_api.client: - max_redirects: 7 + max_redirects: 5 -Injecting the HTTP Client Into Services +Injecting the HTTP Client into Services ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If your application only defines one HTTP client, you can inject it into any -service by type-hinting a constructor argument with the +If your application only needs one HTTP client, you can inject the default one +into any services by type-hinting a constructor argument with the :class:`Symfony\\Contracts\\HttpClient\\HttpClientInterface`:: use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -476,18 +621,11 @@ If you have several clients, you must use any of the methods defined by Symfony to ref:`choose a specific service `. Each client has a unique service named after its configuration. -.. code-block:: yaml - - # config/services.yaml - services: - # ... - - # whenever a service type-hints HttpClientInterface, inject the GitHub client - Symfony\Contracts\HttpClient\HttpClientInterface: '@some_api.client' - - # inject the HTTP client called 'crawler' into this argument of this service - App\Some\Service: - $someArgument: '@crawler.client' +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`` +service into your autowired classes. Testing HTTP Clients and Responses ---------------------------------- @@ -496,8 +634,8 @@ 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. -The first way of using ``MockHttpClient`` is to configure the set of responses -to return using its constructor:: +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:: use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\MockResponse; From 73c26f67b73bf366ee858047b9e597194a5c81d2 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 3 Jun 2019 22:59:40 +0200 Subject: [PATCH 197/499] fix constraint reference YAML config syntax --- reference/constraints/Negative.rst | 2 +- reference/constraints/NegativeOrZero.rst | 2 +- reference/constraints/Positive.rst | 2 +- reference/constraints/PositiveOrZero.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/reference/constraints/Negative.rst b/reference/constraints/Negative.rst index c90a1fb1c98..4e3edee87f2 100644 --- a/reference/constraints/Negative.rst +++ b/reference/constraints/Negative.rst @@ -47,7 +47,7 @@ The following constraint ensures that the ``withdraw`` of a bank account App\Entity\TransferItem: properties: withdraw: - - Negative + - Negative: ~ .. code-block:: xml diff --git a/reference/constraints/NegativeOrZero.rst b/reference/constraints/NegativeOrZero.rst index 15d0926bc5d..5a77a36ab67 100644 --- a/reference/constraints/NegativeOrZero.rst +++ b/reference/constraints/NegativeOrZero.rst @@ -46,7 +46,7 @@ is a negative number or equal to zero: App\Entity\UnderGroundGarage: properties: level: - - NegativeOrZero + - NegativeOrZero: ~ .. code-block:: xml diff --git a/reference/constraints/Positive.rst b/reference/constraints/Positive.rst index b9bef408fa5..bfed77a763c 100644 --- a/reference/constraints/Positive.rst +++ b/reference/constraints/Positive.rst @@ -47,7 +47,7 @@ positive number (greater than zero): App\Entity\Employee: properties: income: - - Positive + - Positive: ~ .. code-block:: xml diff --git a/reference/constraints/PositiveOrZero.rst b/reference/constraints/PositiveOrZero.rst index 70196a6b9fa..cc592f824c6 100644 --- a/reference/constraints/PositiveOrZero.rst +++ b/reference/constraints/PositiveOrZero.rst @@ -46,7 +46,7 @@ is positive or zero: App\Entity\Person: properties: siblings: - - PositiveOrZero + - PositiveOrZero: ~ .. code-block:: xml From 06ef5a3abc858dc2a5e2de756c3a233825449254 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 4 Jun 2019 09:08:13 +0200 Subject: [PATCH 198/499] Fixed typos --- components/http_client.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/http_client.rst b/components/http_client.rst index fff89f7b652..c5a829eae18 100644 --- a/components/http_client.rst +++ b/components/http_client.rst @@ -237,7 +237,7 @@ Advanced Options The :class:`Symfony\\Contracts\\HttpClient\\HttpClientInterface` defines all the options you might need to take full control of the way the request is performed, -including progress monitoring, DSN pre-resolution, timeout, SSL parameters, etc. +including progress monitoring, DNS pre-resolution, timeout, SSL parameters, etc. Processing Responses -------------------- @@ -266,7 +266,7 @@ following methods:: .. note:: ``$response->getInfo()`` is non-blocking: it returns *live* information - about the response. Some of them might not be know yet (e.g. ``http_code``) + about the response. Some of them might not be known yet (e.g. ``http_code``) when you'll call it. .. tip:: @@ -358,7 +358,7 @@ But maybe the 2nd response came back before the 1st? Fully asynchronous operatio require being able to deal with the responses in whatever order they come back. In order to do so, the ``stream()`` method of HTTP clients accepts a list of -responses to monitor. As mentionned :ref:`previously `, +responses to monitor. As mentioned :ref:`previously `, this method yields response chunks as they arrive from the network. By replacing the "foreach" in the snippet with this one, the code becomes fully async:: @@ -396,7 +396,7 @@ option:: The ``default_socket_timeout`` PHP ini setting is used if the option is not set. -The option can be overriden by using the 2nd argument of the ``stream()`` method. +The option can be overridden by using the 2nd argument of the ``stream()`` method. This allows monitoring several responses at once and applying the timeout to all of them in a group. If all responses become inactive for the given duration, the method will yield a special chunk whose ``isTimeout()`` will return ``true``:: @@ -416,14 +416,14 @@ response and get remaining contents that might come back in a new timeout, etc. .. note:: - Timeouts control how long one is willing to wait *while the HTTP transation + Timeouts control how long one is willing to wait *while the HTTP transaction is idle*. Big responses can last as long as needed to complete, provided they remain active during the transfer and never pause for longer than specified. Dealing with Network Errors ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Network errors (broken pipe, failed DSN resolution, etc.) are thrown as instances +Network errors (broken pipe, failed DNS resolution, etc.) are thrown as instances of :class:`Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface`. First of all, you don't *have* to deal with them: letting errors bubble to your @@ -618,7 +618,7 @@ into any services by type-hinting a constructor argument with the } If you have several clients, you must use any of the methods defined by Symfony -to ref:`choose a specific service `. Each client +to :ref:`choose a specific service `. Each client has a unique service named after its configuration. Each scoped client also defines a corresponding named autowiring alias. From 963e6f8fd8ce18547d227f5d780fc73fa9c6db24 Mon Sep 17 00:00:00 2001 From: Andy Palmer Date: Wed, 5 Jun 2019 11:14:56 +0100 Subject: [PATCH 199/499] Update mailer.rst When defining twig paths the path must be the key and the namespace must be the value. The current documentation throws an error. --- mailer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mailer.rst b/mailer.rst index 01a69800cd9..9cebbdc4f7c 100644 --- a/mailer.rst +++ b/mailer.rst @@ -453,7 +453,7 @@ called ``css`` that points to the directory where ``email.css`` lives: paths: # point this wherever your css files live - css: '%kernel.project_dir%/assets/css' + '%kernel.project_dir%/assets/css': css .. _mailer-markdown: From fdd5e029b8a52ff9d0f734c3df872a8738a32e96 Mon Sep 17 00:00:00 2001 From: Gauthier Gilles Date: Wed, 5 Jun 2019 15:47:00 +0200 Subject: [PATCH 200/499] auth_basic is a scalar type --- 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 56906d61ab9..4ac4337478a 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -733,11 +733,11 @@ service into your autowired classes. auth_basic .......... -**type**: ``array`` +**type**: ``string`` The username and password used to create the ``Authorization`` HTTP header used in HTTP Basic authentication. The value of this option must follow the -format ``['username', 'password']``. +format ``username:password``. auth_bearer ........... From 48dffe50eb1cf06c99e2a2df50e010506ab2ddd3 Mon Sep 17 00:00:00 2001 From: Andy Palmer Date: Wed, 5 Jun 2019 19:53:48 +0100 Subject: [PATCH 201/499] Update mailer.rst Replace twig filter tag with apply tag --- mailer.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mailer.rst b/mailer.rst index 01a69800cd9..8b35e6a68e0 100644 --- a/mailer.rst +++ b/mailer.rst @@ -414,7 +414,7 @@ with the ``inline_css`` filter: .. code-block:: html+twig - {% filter inline_css %} + {% apply inline_css %}