diff --git a/UPGRADE-2.1.md b/UPGRADE-2.1.md index 47b1dda99d..a44c018add 100644 --- a/UPGRADE-2.1.md +++ b/UPGRADE-2.1.md @@ -3,299 +3,341 @@ UPGRADE FROM 2.0 to 2.1 ### General -* assets_base_urls and base_urls merging strategy has changed + * The merging strategy for `assets_base_urls` and `base_urls` has changed. - Unlike most configuration blocks, successive values for - ``assets_base_urls`` will overwrite each other instead of being merged. - This behavior was chosen because developers will typically define base - URL's for each environment. Given that most projects tend to inherit - configurations (e.g. ``config_test.yml`` imports ``config_dev.yml``) - and/or share a common base configuration (i.e. ``config.yml``), merging - could yield a set of base URL's for multiple environments. + Unlike most configuration blocks, successive values for `assets_base_urls` + will overwrite each other instead of being merged. This behavior was chosen + because developers will typically define base URL's for each environment. + Given that most projects tend to inherit configurations (e.g. + `config_test.yml` imports `config_dev.yml`) and/or share a common base + configuration (i.e. `config.yml`), merging could yield a set of base URL's + for multiple environments. -### [HttpFoundation] +### HttpFoundation -* moved management of the locale from the Session class to the Request class + * Locate management was moved from the Session class to the Request class. - Configuring the default locale: + ##### Configuring the default locale Before: - framework: - session: - default_locale: fr + ``` + framework: + session: + default_locale: fr + ``` After: - framework: - default_locale: fr + ``` + framework: + default_locale: fr + ``` - Retrieving the locale from a Twig template: + ##### Retrieving the locale from a Twig template Before: `{{ app.request.session.locale }}` or `{{ app.session.locale }}` After: `{{ app.request.locale }}` - Retrieving the locale from a PHP template: + ##### Retrieving the locale from a PHP template Before: `$view['session']->getLocale()` After: `$view['request']->getLocale()` - Retrieving the locale from PHP code: + ##### Retrieving the locale from PHP code Before: `$session->getLocale()` After: `$request->getLocale()` -* Method `equals` of `Symfony\Component\Security\Core\User\UserInterface` has - moved to `Symfony\Component\Security\Core\User\EquatableInterface`. +### Security - You have to change the name of the `equals` function in your implementation - of the `User` class to `isEqualTo` and implement `EquatableInterface`. - Apart from that, no other changes are required to make it behave as before. - Alternatively, you can use the default implementation provided - by `AbstractToken:hasUserChanged` if you do not need any custom comparison logic. - In this case do not implement the interface and remove your comparison function. + * `Symfony\Component\Security\Core\User\UserInterface::equals()` has moved to + `Symfony\Component\Security\Core\User\EquatableInterface::isEqualTo()`. + + You must rename the `equals()` method in your implementation of the `User` + class to `isEqualTo()` and implement `EquatableInterface`. Apart from that, + no other changes are required. + + Alternatively, you may use the default implementation provided by + `AbstractToken::hasUserChanged()` if you have no need of custom comparison + logic. In this case, do not implement `EquatableInterface` and remove your + comparison method. Before: - class User implements UserInterface - { - // ... - public function equals(UserInterface $user) { /* ... */ } - // ... - } + ``` + class User implements UserInterface + { + // ... + public function equals(UserInterface $user) { /* ... */ } + // ... + } +``` After: - class User implements UserInterface, EquatableInterface - { - // ... - public function isEqualTo(UserInterface $user) { /* ... */ } - // ... - } + ``` + class User implements UserInterface, EquatableInterface + { + // ... + public function isEqualTo(UserInterface $user) { /* ... */ } + // ... + } + ``` -* Form children aren't automatically validated anymore. That means that you - explicitely need to set the `Valid` constraint in your model if you want to - validate associated objects. +### Form and Validator + + * Child forms are no longer automatically validated. That means that you must + explicitly set the `Valid` constraint in your model if you want to validate + associated objects. If you don't want to set the `Valid` constraint, or if there is no reference from the data of the parent form to the data of the child form, you can - enable BC behaviour by setting the option "cascade_validation" to `true` on - the parent form. + enable BC behavior by setting the `cascade_validation` form option to `true` + on the parent form. -* Changed implementation of choice lists + * Changed implementation of choice lists - ArrayChoiceList was replaced. If you have custom classes that extend - this class, you can now extend SimpleChoiceList. + ArrayChoiceList was replaced. If you have custom classes that extend this + class, you must now extend SimpleChoiceList. Before: - class MyChoiceList extends ArrayChoiceList + ``` + class MyChoiceList extends ArrayChoiceList + { + protected function load() { - protected function load() - { - parent::load(); - - // load choices - - $this->choices = $choices; - } + parent::load(); + + // load choices + + $this->choices = $choices; } + } + ``` After: - class MyChoiceList extends SimpleChoiceList + ``` + class MyChoiceList extends SimpleChoiceList + { + public function __construct() { - public function __construct() - { - // load choices - - parent::__construct($choices); - } + // load choices + + parent::__construct($choices); } + } + ``` - If you need to load the choices lazily - that is, as soon as they are - accessed for the first time - you can extend LazyChoiceList instead. + If you need to load the choices lazily -- that is, as soon as they are + accessed for the first time -- you can extend LazyChoiceList instead. - class MyChoiceList extends LazyChoiceList + ``` + class MyChoiceList extends LazyChoiceList + { + protected function loadChoiceList() { - protected function loadChoiceList() - { - // load choices - - return new SimpleChoiceList($choices); - } + // load choices + + return new SimpleChoiceList($choices); } + } + ``` PaddedChoiceList, MonthChoiceList and TimezoneChoiceList were removed. - Their functionality was merged into DateType, TimeType and - TimezoneType. + Their functionality was merged into DateType, TimeType and TimezoneType. - EntityChoiceList was adapted. The methods `getEntities`, - `getEntitiesByKeys`, `getIdentifier` and `getIdentifierValues` were - removed/made private. Instead of the first two, you can now use - `getChoices` and `getChoicesByValues`. For the latter two, no + EntityChoiceList was adapted. The methods `getEntities()`, + `getEntitiesByKeys()`, `getIdentifier()` and `getIdentifierValues()` were + removed or made private. Instead of the first two, you can now use + `getChoices()` and `getChoicesByValues()`. For the latter two, no replacement exists. -* The strategy for generating the HTML attributes "id" and "name" - of choices in a choice field has changed + * The strategy for generating the `id` and `name` HTML attributes for choices + in a choice field has changed. Instead of appending the choice value, a generated integer is now appended - by default. Take care if your Javascript relies on that. If you can - guarantee that your choice values only contain ASCII letters, digits, - letters, colons and underscores, you can restore the old behaviour by - setting the option "index_strategy" of the choice field to - `ChoiceList::COPY_CHOICE`. + by default. Take care if your JavaScript relies on the old behavior. If you + can guarantee that your choice values only contain ASCII letters, digits, + colons and underscores, you can restore the old behavior by setting the + `index_strategy` choice field option to `ChoiceList::COPY_CHOICE`. -* The strategy for generating the HTML attributes "value" of choices in a - choice field has changed + * The strategy for generating the `value` HTML attribute for choices in a + choice field has changed. - Instead of using the choice value, a generated integer is now stored. - Again, take care if your Javascript reads this value. If your choice field - is a non-expanded single-choice field, or if the choices are guaranteed not - to contain the empty string '' (which is the case when you added it manually + Instead of using the choice value, a generated integer is now stored. Again, + take care if your JavaScript reads this value. If your choice field is a + non-expanded single-choice field, or if the choices are guaranteed not to + contain the empty string '' (which is the case when you added it manually or when the field is a single-choice field and is not required), you can - restore the old behaviour by setting the option "value_strategy" to - `ChoiceList::COPY_CHOICE`. + restore the old behavior by setting the `value_strategy` choice field option + to `ChoiceList::COPY_CHOICE`. -* In the template of the choice type, the structure of the "choices" variable - has changed + * In the choice field type's template, the structure of the `choices` variable + has changed. - "choices" now contains ChoiceView objects with two getters `getValue` - and `getLabel` to access the choice data. The indices of the array - store an index whose generation is controlled by the "index_generation" - option of the choice field. + The `choices` variable now contains ChoiceView objects with two getters, + `getValue()` and `getLabel()`, to access the choice data. The indices of the + array are controlled by the choice field's `index_generation` option. Before: - {% for choice, label in choices %} - - {% endfor %} + ``` + {% for choice, label in choices %} + + {% endfor %} + ``` After: - {% for choice in choices %} - - {% endfor %} + ``` + {% for choice in choices %} + + {% endfor %} + ``` -* In the template of the collection type, the default name of the prototype - field has changed from "$$name$$" to "__name__" + * In the collection type's template, the default name of the prototype field + has changed from `$$name$$` to `__name__`. - For custom names, no dollars are prepended/appended anymore. You are advised - to prepend and append double underscores wherever you have configured the - prototype name manually. + For custom names, dollar signs are no longer prepended and appended. You are + advised to prepend and append two underscores wherever you specify a value + for the field's `prototype_name` option. Before: - $builder->add('tags', 'collection', array('prototype' => 'proto')); - - // results in the name "$$proto$$" in the template + ``` + $builder->add('tags', 'collection', array('prototype' => 'proto')); + + // results in the name "$$proto$$" in the template + ``` After: - $builder->add('tags', 'collection', array('prototype' => '__proto__')); + ``` + $builder->add('tags', 'collection', array('prototype' => '__proto__')); + + // results in the name "__proto__" in the template + ``` - // results in the name "__proto__" in the template + * The methods `setMessage()`, `getMessageTemplate()` and + `getMessageParameters()` in the Constraint class were deprecated. -* The methods `setMessage`, `getMessageTemplate` and `getMessageParameters` - in Constraint were deprecated - - If you have implemented custom validators, you should use either of the - `addViolation*` methods of the context object instead. + If you have implemented custom validators, you should use the + `addViolation()` method on the `ExecutionContext` object instead. Before: - public function isValid($value, Constraint $constraint) - { - // ... - if (!$valid) { - $this->setMessage($constraint->message, array( - '{{ value }}' => $value, - )); - - return false; - } + ``` + public function isValid($value, Constraint $constraint) + { + // ... + if (!$valid) { + $this->setMessage($constraint->message, array( + '{{ value }}' => $value, + )); + + return false; } + } + ``` After: - public function isValid($value, Constraint $constraint) - { - // ... - if (!$valid) { - $this->context->addViolation($constraint->message, array( - '{{ value }}' => $value, - )); - - return false; - } + ``` + public function isValid($value, Constraint $constraint) + { + // ... + if (!$valid) { + $this->context->addViolation($constraint->message, array( + '{{ value }}' => $value, + )); + + return false; } + } + ``` -* The options passed to `getParent` of the form types don't contain default - options anymore + * The options passed to the `getParent()` method of form types no longer + contain default options. - You should check with `isset` if options exist before checking their value. + You should check if options exist before attempting to read their value. Before: - public function getParent(array $options) - { - return 'single_text' === $options['widget'] ? 'text' : 'choice'; - } + ``` + public function getParent(array $options) + { + return 'single_text' === $options['widget'] ? 'text' : 'choice'; + } + ``` After: - public function getParent(array $options) - { - return isset($options['widget']) && 'single_text' === $options['widget'] ? 'text' : 'choice'; - } + ``` + public function getParent(array $options) + { + return isset($options['widget']) && 'single_text' === $options['widget'] ? 'text' : 'choice'; + } + ``` -* Flash Messages now returns and array based on type (the old method are still available but deprecated) - - Before (Twig): - - {% if app.session.hasFlash('notice') %} -
- {{ app.session.flash('notice') }} -
- {% endif %} - - After (Twig): - - {% if app.session.flashbag.has('notice') %} -
- {{ app.session.flashbag.get('notice') }} -
- {% endif %} - - Again you can process all flash messages in one go with - - {% for type, flashMessage in app.session.flashbag.all() %} -
- {{ flashMessage }} -
- {% endforeach %} - -* Session storage drivers - - Session storage drivers should inherit from - `Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage` - and no longer should implement `read()`, `write()`, `remove()` which were removed from the - `SessionStorageInterface`. - - Any session storage driver that wants to use custom save handlers should - implement `Symfony\Component\HttpFoundation\Session\Storage\SessionHandlerInterface` - -* The methods `add`, `remove`, `setParent`, `bind` and `setData` in class Form - now throw an exception if the form is already bound + * The `add()`, `remove()`, `setParent()`, `bind()` and `setData()` methods in + the Form class now throw an exception if the form is already bound. If you used these methods on bound forms, you should consider moving your - logic to an event listener listening to either of the events - FormEvents::PRE_BIND, FormEvents::BIND_CLIENT_DATA or - FormEvents::BIND_NORM_DATA instead. + logic to an event listener that observes one of the following events: + `FormEvents::PRE_BIND`, `FormEvents::BIND_CLIENT_DATA` or + `FormEvents::BIND_NORM_DATA`. + +### Session + + * Flash messages now return an array based on their type. The old method is + still available but is now deprecated. + + ##### Retrieving the flash messages from a Twig template + + Before: + + ``` + {% if app.session.hasFlash('notice') %} +
+ {{ app.session.flash('notice') }} +
+ {% endif %} + ``` + + After: + + ``` + {% if app.session.flashbag.has('notice') %} +
+ {{ app.session.flashbag.get('notice') }} +
+ {% endif %} + ``` + + You can process all flash messges in a single loop with: + + ``` + {% for type, flashMessage in app.session.flashbag.all() %} +
+ {{ flashMessage }} +
+ {% endforeach %} + ``` + + * Session storage drivers should inherit from + `Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage` + and should no longer implement `read()`, `write()`, and `remove()`, which + were removed from `SessionStorageInterface`. + + Any session storage driver that wants to use custom save handlers should + implement `Symfony\Component\HttpFoundation\Session\Storage\SessionHandlerInterface`.