Symfony 8.2 is a minor release. According to the Symfony release process, there should be no significant
backward compatibility breaks. Minor backward compatibility breaks are prefixed in this document with
[BC BREAK], make sure your code is compatible with these entries before upgrading.
Read more about this in the Symfony documentation.
If you're upgrading from a version below 8.1, follow the 8.1 upgrade guide first.
- Add argument
$useEsmtoImportMapConfigReader::createRemoteEntry()
- Add
$projectIdconstructor parameter toCrowdinProvider
UniqueEntitynow throws aConstraintDefinitionExceptionwhen a checked field holds an array or is a to-many association and the defaultfindByrepository method is used. Such fields were silently validated against a query that could not match. Use therepositoryMethodoption to provide a method that can query them- Deprecate
DoctrineCloseConnectionMiddlewarein favor ofDoctrineDbalCloseConnectionMiddleware,DoctrineOpenTransactionLoggerMiddlewarein favor ofDoctrineDbalOpenTransactionLoggerMiddleware, andDoctrinePingConnectionMiddlewarein favor ofDoctrineDbalPingConnectionMiddleware. Those new middlewares target DBAL connections instead of entity managers. They are instantiated with aConnectionRegistryinstead of aManagerRegistry, and connection names (either one or a list) instead of an entity manager name. Passing no name now targets every DBAL connection, where the deprecated close and logger middlewares targeted the connection of the default entity manager, and the deprecated ping middleware targeted the connections of every entity manager. Beware thatDoctrineDbalOpenTransactionLoggerMiddlewaretakes its logger as second argument and its connection names as third, whereDoctrineOpenTransactionLoggerMiddlewaretook the entity manager name as second argument and its logger as third. Also note thatDoctrineDbalPingConnectionMiddlewaredoes not reset closed entity managers as its deprecated counterpart did: workers already reset them between messages
- Add
createStepGroup()method toFormFlowBuilderInterface; implementations not extending the defaultFormFlowBuildermust implement it - Add
setGroup(),addStep()andremoveStep()methods toStepFlowBuilderConfigInterface; implementations not extending the defaultStepFlowBuildermust implement them - Add
isGroup(),getSteps(),hasStep()andgetStep()methods toStepFlowConfigInterface; implementations not extending the defaultStepFlowBuildermust implement them - [BC BREAK] Children that use the
form_attroption now carry the id the themes render on the<form>element instead of the id of the element wrapping the fields, so that the reference resolves. That id is theattr.idof the root form when the application set one, the string given toform_attrwhen the option is a string, wherever it sits in the form tree, andform_<root id>otherwise. Forms that do not useform_attrare unaffected: theform_idview variable staysnullwhen nothing references it - Deprecate the
regionsoption ofTimezoneType, it has had no effect since 5.0 and will be removed in 9.0 TimezoneTypewith theintloption enabled now offers the identifier PHP reports as canonical when ICU keys a zone and its legacy aliases under one display name, soAsia/Kolkatais offered whereAsia/Calcuttaused to be. The aliases stay submittable and are resolved to the offered identifier, so a stored value keeps designating the same choice, but reading it back returns the offered identifierTimezoneTypenow resolvesUTCandEtc/UTCto each other, theintloption deciding which one is offered, where submitting the one the option does not offer used to be rejected
- Deprecate the
framework.ideconfig option, use theSYMFONY_IDEenv var instead - BrowserKit assertions are no longer verbose by default. Failed response assertions no longer include the response body unless
setBrowserKitAssertionsAsVerbose(true)is called orverbose: trueis passed to the assertion. - Deprecate the
framework.fragments.hinclude_default_templateconfig option and thefragment.renderer.hinclude.global_templateparameter; use theesiorinlinefragment renderer, or Symfony UX Turbo, instead
- [BC BREAK] Widen the type of the
$bufferargument ofHttpOptions::buffer()frombooltomixed, so that the stream and closure forms the option accepts can be passed; a class extendingHttpOptionsand overriding that method must widen it too
- Add argument
$versiontoUriSigner::sign(),UriSigner::check(),UriSigner::checkRequest(), andUriSigner::verify() - Deprecate the
Request::$trustedHostsproperty, it is never populated anymore since trusted hosts are matched against a single combined regexp, and will be removed in 9.0. Populating it makesgetHost()trigger a deprecation; reading it is not reported, since PHP provides no way to intercept access to a static property
- Deprecate the
HIncludeFragmentRendererclass, use theEsiFragmentRendererorInlineFragmentRenderer, or Symfony UX Turbo, instead
- Add argument
$advisorytoStoreFactory::createStore()
- Deprecate passing
LocoProviderandLocoProviderFactoryconstructor a$defaultLocaleargument. It has no effect and can be removed. - Deprecate passing no domains or
*toLocoProvider::read(), configure your loco provider domains as an associative array with an empty string key and*as value
-
[AhaSend] Deprecate sending through the legacy v1 API, use a v2 API key and add your account id to the DSN
-
Deprecate sending an S/MIME message unencrypted when a recipient has no certificate (the default
SmimeEncryptedMessageListener::ON_MISSING_CERTIFICATE_SEND_UNENCRYPTEDbehavior); it will throw in 9.0. Set theon_missing_certificateoption (or theX-SMime-Encryptheader) tofail,encryptorskip:framework: mailer: smime_encrypter: on_missing_certificate: 'fail'
-
DkimSignedMessageListenernow listens with priority-228instead of-128, so that DKIM signs the S/MIME encrypted message instead of racingSmimeEncryptedMessageListenerfor the same priority. Use the newDkimSignedMessageListener::PRIORITY,SmimeSignedMessageListener::PRIORITYandSmimeEncryptedMessageListener::PRIORITYconstants if you register listeners that must run around them.
-
The Amazon SQS transport no longer deduplicates the messages sent to a FIFO queue on their content: the
MessageDeduplicationIdsent by default is now unique per message, so dispatching the same message twice within five minutes delivers it twice. To keep deduplicating, set the id explicitly withAmazonSqsFifoStampor with a message implementingMessageDeduplicationAwareInterface(together withAddFifoStampMiddleware); theContentBasedDeduplicationattribute of the queue alone is not enough, as an explicit id overrides it. -
RedispatchMessagenow dispatches to the senders configured for the message (viaframework.messenger.routingor#[AsMessage]) when$transportNamesis empty, instead of sending to no sender at all. Code that relied onnew RedispatchMessage($message), or on an empty array or string, to force in-process handling of a message that also has a configured route must now carry an emptyTransportNamesStampon the inner envelope:new RedispatchMessage(new Envelope($message, [new TransportNamesStamp([])]))
Note that a message sent to a transport is no longer handled in process, so
RedispatchMessageHandlerreturnsnullfor it instead of the result of the handler
- Deprecate
NovuSubscriberRecipient::getOverrides()and its$overridesconstructor parameter, pass overrides toNovuOptionsinstead - Deprecate declaring
getAdminRecipients()on aNotifierInterfaceimplementation without implementingAdminRecipientsProviderInterface
-
Deprecate
Schedule::with(). It returns a schedule that keeps only the event dispatcher, so a lock or a state set on the original schedule is silently dropped, and the resulting schedule then runs unlocked.To derive a schedule from another one, clone it. The clone shares the dispatcher, the lock and the state, and its list of messages is independent, so adding to one does not affect the other:
$new = clone $schedule; $new->add($message);
To build an unrelated schedule, which is what
with()actually did, construct one:// before $new = $schedule->with($message); // after $new = (new Schedule($dispatcher))->add($message);
- [BC BREAK] A failing
#[IsCsrfTokenValid]attribute now throwsSymfony\Component\Security\Http\Exception\InvalidCsrfTokenException, which extendsHttpExceptionand carries a 403 status, instead ofSymfony\Component\Security\Core\Exception\InvalidCsrfTokenException, which extendsAuthenticationException. The firewall no longer turns the failure into a login redirect or a 401, and code catching theSecurity\Coreexception for this case must catch theSecurity\Httpone instead - Add argument
$targetUritoImpersonateUrlGenerator::generateImpersonationPath()andImpersonateUrlGenerator::generateImpersonationUrl() - Add argument
$parameterstoLoginLinkHandlerInterface::createLoginLink() - Add argument
$parameterstoSignatureHasher::computeSignatureHash(),SignatureHasher::acceptSignatureHash()andSignatureHasher::verifySignatureHash()
- Deprecate the
remember_meoption of theform_login,json_login,login_link, andaccess_tokenauthenticators, as it has no effect - Deprecate configuring an access control rule with many
roles, useallow_ifor role hierarchy instead - Deprecate configuring both an access control rule
allow_ifandroles, updateallow_ifinstead - A service used as a firewall
success_handlerorfailure_handleris now wired as-is, so decorating it takes effect where it used to be silently ignored. Such a decorator must forwardsetOptions(), andsetFirewallName()for success handlers, to the service it decorates whenever that service relies on them, asDefaultAuthenticationSuccessHandlerandDefaultAuthenticationFailureHandlerdo. Without forwarding, the authenticator options and the session target path are lost, and a successful login redirects to/
- Deprecate denormalizing an array that is not a list into a
list-typed property, in version 9.0 aSymfony\Component\Serializer\Exception\NotNormalizableValueExceptionwill be thrown when the input does not satisfyarray_is_list() - Denormalize the elements of a union-typed collection, e.g.
array<Foo|Bar>, instead of returning the raw data. An element that matches no member of the union, or a key whose type does not match, now throws instead of being returned as-is
FilteringProvider::read()now returns an emptyTranslatorBagwhen none of the requested locales match the configured ones, and a bag of empty catalogues when no requested domain matches, instead of delegating to the wrapped provider
- [BC BREAK] Add argument
$multiselectas the third argument ofSelectListWidget::__construct(), moving$keybindingsto fourth position
form_start()renders anidattribute on the<form>element when a child uses theform_attroption, taken from the newform_idview variable. Forms that do not use it render as before. Setattr.idon the root form to choose the id, orattr: {id: false}to render none. A custom theme overriding theform_startblock renders no id until that block is updated- Deprecate the
render_hinclude()Twig function; userender_esi()orrender(), or Symfony UX Turbo, instead
-
Add argument
$restrictGroupstoValid::__construct() -
[BC BREAK] Remove the
GroupSequence::$cascadedGroupproperty, it has had no effect since the validator stopped reading it in 2014, and reading it has thrown since 7.4 typed it without a default -
Add argument
$cascadeCurrentGrouptoGroupSequenceProvider::__construct() -
The
Fileconstraint no longer narrows the configuredmimeTypesoption with mime types auto-derived from the matched extension whenextensionsis also configured. The two options are now checked independently:extensionsvalidates the file extension, andmimeTypesvalidates the detected mime type.In previous versions, the effective mime-type list was narrowed to the mime types auto-derived from the matching extension. For example, a CSV file detected as
text/plaincould be rejected by this constraint because themimeTypeslist was narrowed to the mime types derived fromcsv:#[Assert\File( extensions: ['csv'], mimeTypes: ['text/csv', 'text/plain'], )]
In Symfony 8.2, the configured
mimeTypeslist is used as-is, while thecsvextension is still enforced separately.