This week, Symfony 5.4.55, 6.4.49, 7.4.22, and 8.1.10 maintenance versions were released. We also released Symfony AI 1.0.0-BETA1 and kicked off the Symfony AI & MCP Hackathon, which runs until November 22. Meanwhile, we kept publishing articles about Symfony 8.2 features, such as the Messenger inbox, cross-application messaging, security expressions everywhere, and recovering from controller attribute failures. Finally, we shared the schedule highlights of SymfonyCon Warsaw 2026, which starts in less than a month.
Symfony development highlights
This week, 344 pull requests were merged (201 in code, 57 in docs, 35 in UX and 51 in AI) and 90 issues were closed (35 in code, 35 in docs, 3 in UX and 17 in AI). Excluding merges, 83 authors made additions and deletions. See details for code, docs, UX and AI.
- 2cbd264: [Routing] don't ignore route conditions that are "0"
- b759b96: [Intl] update the ICU data to 79.1
- 8953ff8: [PropertyAccess] fix writing SimpleXMLElement children and dynamic properties of #[AllowDynamicProperties] classes
- ab31573: [HttpClient] fix retry delays longer than the idle timeout
- 9cb24a4: [FrameworkBundle] make secrets key rotation safe to interrupt
- c480297: [FrameworkBundle] make secrets key generation and list updates safe to interrupt
- 961a14e: [Console] fix styles that leak out of Table cells
- a5e8914: [Console] fix the alignment of wrapped Table cells and newlines around style tags
- b355d0e: [Console] fix Table header cells that span rows and escaped tags in TableCell
- 3d361b2: [Console] fix style names with uppercase letters not being applied
- 5df5f19: [Intl] fix Timezones::getRawOffset() depending on the default timezone around DST transitions
- 697ccad: [Validator] fix Arabic validation messages and six-form plurals
- c27b996: [SecurityBundle] stop asserting an empty body for the 401 of a rejected access token
- e31a838: [Security] stop logging router errors when a check path does not match the request
- 642ba3e: [Cache] fix items losing their tags when saved after a concurrent invalidation
- 9ac9c8c: [Console] don't format escaped tags again when sections measure their lines
- 2aee1d2: [HttpKernel] don't keep the stale container when rebuilding it fails
- e053d90: [HttpClient] fix clearing the DNS cache of pending requests when a traced response is destructed
- 7616683: [HttpClient] fix CurlHttpClient writing the body of a response to stdout when it is canceled during stream()
- d6455a4: [WebProfilerBundle] return a 404 when opening the profiler file viewer without a file
- c24025c: [HttpClient] fix reading a traced CurlResponse as a stream after its decorator is destructed
- 65dedc1: [HttpKernel] fix searching profiles by status code 0
- 08d96a3: [HttpClient] fix getContent() returning a truncated body when the response is canceled while it reads it
- 2068107: [HttpClient] fix AsyncResponse throwing a LogicException when it is canceled while streaming
- fd88ffb: reject trailing newlines in Content-Disposition fallbacks
- b77add9: [HttpClient] let PHP destruct the response decorated by TraceableResponse
- b4e281d: [WebProfilerBundle] reset the profiler Twig extension between requests
- ab2829d: [WebProfilerBundle] reset the CSP handler between requests
- ee01c09: [AssetMapper] fix
importmap:removedeleting the files of local entries - 6333d9e: [Console] fix Table cells that span rows when they follow a cell that spans columns
- 719bc7b: [Console] fix setRow(), setColumnMaxWidth() and consecutive rowspans in Table
- dcfde2d: [Validator] show the count in the word count messages of locales with a single plural form
- 2010998: [Messenger] preserve handled stamps when a batch handler nacks
- 6cc97d2: [Messenger] don't hide handler failures when a batch handler acks the same message
- 248f04f: [Form] preserve the Unix epoch in date string transformation
- ad74014: [Messenger] let the worker flush the batches that contain a failed message
- 0be4996: [Messenger] retry the messages whose batch was flushed during a failed dispatch
- 2906b65: [Messenger] wait for all batch handlers before acknowledging a message
- c860273: [Serializer] fix denormalizing a data URI ending with slashes to a File
- 029da40: [Translation] don't read provider responses as file paths
- 134ec20: [Cache] add support for relay 0.61
- 24a5787: [PropertyAccess] handle uninitialized properties of anonymous classes on PHP 8.6
- 0842b1f: [BrowserKit] expire cookies dated at the Unix epoch
- 984e433: [BrowserKit] match cookies across equivalent IPv6 addresses
- 22e723d: [HttpKernel] compute #[Cache] durations without daylight saving time
- fb07185: [JsonStreamer] fix explicit null handling in the string reader and reject it on non-nullable types
- 8efadb6: [Console] fix raw token stripping when an option value matches the command
- 564aeac: [Messenger] allow installing the Redis bridge with only ext-relay
- 9c85148: [JsonStreamer] reject scalar values of the wrong type instead of converting them
- 0f141ae: [JsonPath] fix open-ended slices in the path builder
- 042fa2e: [JsonPath] fix negative-step slices and reject invalid slices on objects
- dbdaf9e: [Console] fix Helper::removeDecoration() keeping escaped > and trailing backslashes
- 3b4baae: [Messenger] reject non-integer fetch sizes
- 02b7886: [RateLimiter] preserve calendar-aligned reservations across periods
- 183df79: [RateLimiter] apply a changed limit to stored calendar-aligned windows
- 7c04464: [Messenger] release handled envelopes without waiting for the garbage collector
- c544670: [Console] register service argument locators under the resolved names of commands
- 578fcf5: [KeyManagement] harden envelope and stored key authentication
- d2df599: [KeyManagement] simplify rewrapping and report a missing store secret at compile time
- de8d949: [Messenger] apply --max after the filters in
messenger:showandmessenger:failed:show - cba43e5: [Messenger] enable TCP_NODELAY on the MySQL connections of the AMPHP SQL transport
- be0307c: [Webhook] don't require the HttpClient component to enable no_private_network
- 037760b: [Messenger] fix the AMPHP SQL transport reading every pending message with MySQL
- 11eabfd: [Messenger] fix the AMPHP SQL transport reading every delayed message with PostgreSQL
- d7ad321: [FrameworkBundle] read $_SERVER before $_ENV in KernelTestCase
- 3524218: [Intl] store the ICU data in a more compact way
- 70e97e2: [Intl] add a prune script to remove the data of unused locales
- ef9a963: [FrameworkBundle] add the
debug:autoconfigurationcommand - 9a01f50: [SecurityBundle] serve the protected resource metadata with Access-Control-Allow-Origin: *
- f30bf0a: [Security] add a text/plain body to the 401 and 403 responses of access_token firewalls
- 5d10026: [Config, SecurityBundle] make the resource of resource_metadata work across environments
- 8f35b8d: [Yaml] improve PHPDoc documentation
- 49d8ea3: [Messenger] preserve locale routing context for async messages
- 2e82606: [DependencyInjection] merge configs forwarded by extension aliases in load order
- 6a4f6a2: [KeyManagement] rewrap data keys through wrapDataKey(), not encrypt()
- f6b04e8: [Scheduler] throw at compile time when the method of a task does not exist
- 7b237c8: [DomCrawler] reduce allocations when looking up form fields
- bc32bf9: [OptionsResolver] Short-circuit failed plain type checks
- 15ee23e: [JsonPath] append token results without repeated array merges
- 1326877: [HttpKernel, Security] let controllers handle the failures of their attributes
- c578580: [Config] avoid shifting serialized glob resource data
- 710c327: [JsonPath] accumulate recursive traversal results in one array
- f6fddb6: [ObjectMapper] pass the names of the mapped properties to mapping-aware transformers
- 4a6928d: [Form] guess renamed fields from their mapped properties
- 645cf05: [AssetMapper] log a warning when the compiled import map is missing
- 42cc149: [JsonSchema] preserve boolean subschemas during serialization
- 464917b: [JsonSchema] inline references in siblings of $ref
- ac5b0fe: [JsonSchema] handle boolean subschemas in anyOf branches and Choice items
- b1f0776: [JsonSchema] encode maps as JSON objects and keep the values of non-schema keywords as is
- a8613b9: [JsonSchema] keep the keywords of the definition when flattening a $ref that has siblings
- 20f229a: [ErrorHandler] use get_exception_handler() when handling fatal errors
- 67752fa: [Messenger] process a full batch in a dispatch of its own
- 70951de: [Tui] add support for the Program Status Protocol (OSC 7501)
- 8187890: [Security] let target_route apply to impersonation URLs built for a switch_user path
- 693991e: [HttpFoundation] read the current request of RequestStack without end()
- 2b8cdc4: [BrowserKit] preserve host-only cookies in string representations
- 3a79115: [KeyManagement] add KMIP 2.1 support
- 1ccc8b7: [KeyManagement] add ChaCha20-Poly1305 support to KMIP
Symfony UX development highlights
- 8e6c9a6: [Toolkit] warn about copy-files destinations that skip the installation placeholders
- 61b49f1: [Toolkit, Common] add password-visibility recipe
- 8b0127d: [LiveComponent] look up the Doctrine manager of an entity class once
- 175bb48: [CI] run only the tests of the packages a pull request affects
- 462ab9b: [CI] run the tests of the bridges once their package is done
- ed98f37: [Pkg] move the tooling devDependencies of the packages to the root package.json
- 5411092: [Toolkit] fix the URL of the Flowbite kit
- 3199e91: [LiveComponent] keep the route and its defaults on batch action sub-requests
- 5edc329: [Turbo] update the docs
- aacc82a: [Router, Translator] don't load the routes and translations when the container is built
- 29b9641: [Turbo] keep the connected attribute of <turbo-mercure-stream-source> when morphing
- 975c19d: [LiveComponent] fix the default route of live components in the docs
- 923f5fc: [Turbo] link the docblock of TurboStream::refresh() to the page refreshes of Turbo
- d36b8a2: [Image] add the IPX bridge
- f780f35: [TwigComponent] rewrite the pre-lexer around a single scanner
- 48f677c: [TwigComponent] cache null results of computed properties
- 8b1c27a: [TwigComponent] copy the context only when props override it
- 2c45014: [TwigComponent] set the parent template of embedded components before the render
- 4034f54: [TwigComponent] run the outer blocks backtrace once per template method
- 11551c6: [TwigComponent] use the warmed component properties cache
- 0f57f9b: [Image] add the Imagor bridge
- c45cfab: [LiveComponent] reset the LiveResponder between requests
- 9fedbe7: [Css] add the CSS component
- 0b0498e: [Css] document token categories and complete the design tokens page
- 2e15426: [Css] write the value of each color token to the reference file
Symfony AI development highlights
- 91ebc45: [Agent, Platform] add a message store continuing and saving conversations by their ID
- 393262d: [Agent] return an ExecutionInterface that tells where the execution stands
- babf8c5: [AI Bundle, Agent, Chat] move the message store bridges to the Agent component and deprecate Chat
- 5f51ee0: [Demo] keep the conversations of the chats in the agent message stores
- b3579bb: [Platform] fix Higgsfield image uploads and provider error handling
- a414bd3: [AI Bundle, Chat] remove the Chat component
- f620d0f: prep Release v1.0-BETA1
- 15b96fb: [Platform] send an empty object schema for a tool without parameters
- 04714cd: [Platform] add null to the enum of nullable properties in JSON schemas
- b1db57e: [Platform] stream the string answers of MockPlatformFactory when the call streams
- 6319c9b: [Platform, Generic] keep a text to embed as is instead of turning it into messages
- d7667c6: [MCP Bundle] let php-http/discovery install a PSR-17 implementation
- 5bbe9ea: [Mate] recognize php.exe as the interpreter when probing the PHP version
- a76eeaf: [Agent] add ToolErrorException to tell the model why a tool call failed
- 54b57e9: [MCP Bundle] require psr/simple-cache for the cache session store and notification bus
- dc1acce: [Agent] build the text sent to the model with line feeds on every platform
- 070c57b: [Platform, Ollama] send the options of a model name as options, not as part of the name
- e704b28: [Platform] prune models missing from upstream catalogs
- 53967e2: [Platform, Cache] keep the phase of texts in the cache bridge and the recording serializer
- d0f1048: [Platform] yield no partial object for an empty structure
- 5496373: [Platform, Generic] read an error's reason from a top-level "message" too
- 0777441: [Platform] keep the listeners of a stream that TraceablePlatform traces
- 643e02c: [AI Bundle] fix the Doctrine message store alias pointing to a non-existent service
Newest issues and pull requests
- [RFC][ORM] Evaluate a Symfony ORM component against enterprise persistence requirements
- [ErrorHandler][FrameworkBundle][HttpKernel] Log each deprecation only once when not in debug mode
- [Console][Scheduler] Add isolated process execution for scheduled commands
- [Messenger] Add the consumable option of transports
- [HttpKernel][Messenger][WebProfilerBundle] Profile each message consumed by a worker
Symfony Jobs
These are some of the most recent Symfony job offers:
-
Backend Symfony Developer at Hays
Full-time - €50,000 – €55,000 / year
Spain Remote + part-time onsite (Madrid, Spain)
View details -
Symfony Trainer at SensioLabs
Full-time - €50,000 / year
France Remote + part-time onsite (Asnières-sur-Seine, France)
View details -
Lead Symfony Developer at Tenth Revolution Group
Full-time - up to €50,000 / year
France Remote + part-time onsite (Lyon, France)
View details -
CTO for a Symfony project at OpenDecide
Full-time - €75,000 – €85,000 / year
France Remote + part-time onsite (Toulouse, Paris, France)
View details -
Backend Symfony Developer at Opus Recruitment Solutions
Full-time - up to €70,000 / year
France Remote + part-time onsite (Paris, France)
View details
You can publish a Symfony job offer for free on symfony.com.
SymfonyCasts Updates
SymfonyCasts is the official way to learn Symfony. Select a track for a guided path through 100+ video tutorial courses about Symfony, PHP and JavaScript.
This week, SymfonyCasts published the following updates:
They talked about us
- Building a minimal RAG pipeline with Symfony AI
- Sharing a Symfony project in a URL, without storing anything
- Two-factor authentication with Symfony 8.2: one authenticator, one voter, and that's it
- Symfony AI 1.0.0-BETA1 and a hackathon to break it
- Why I Abandoned Legacy CMS Bloat to Build an Unshakable Application Core in PHP 8.4 & Symfony 7.4
- Encrypting columns with Symfony 8.2: what #[Encrypted] protects, and what it doesn't
- 400 or 422? Designing validation errors for a Symfony API
- Usando Symfony TUI + Jev para mostrar un visor de logs interactivo
- Symfony 8.2 : le message n’est jamais parti. Ou il a été traité deux fois.
Call to Action
- Follow Symfony on X, on Mastodon, on Bluesky and on Threads and share this article.
- Subscribe to the Symfony blog RSS and never miss a Symfony story again.