This week, development activity focused on polishing and fixing the new features of the upcoming Symfony 8.2 version. In addition, we showcased some of them, including the new JsonSchema component, signed Messenger transports, safer HTML in translations, and more MongoDB integrations. Meanwhile, we announced more talks for the SymfonyCon Warsaw 2026 conference.

Symfony development highlights

This week, 404 pull requests were merged (286 in code, 34 in docs, 31 in UX and 53 in AI) and 64 issues were closed (25 in code, 19 in docs, 8 in UX and 12 in AI). Excluding merges, 79 authors made additions and deletions. See details for code, docs, UX and AI.

6.4 changelog:

  • 860713b: [DependencyInjection] keep lazy closures lazy when their service is part of a circular reference
  • 6e2082d: [Serializer] fix denormalizing string-keyed collections and unions from XML
  • b6f7c9c: [Console] stop a failed release from wedging the lock of a command
  • 5e4e2de: [Console] fix locking a command again after acquiring its lock failed
  • 4f98c22: [Security, SecurityBundle] decide the checks of an expression for the token being voted on
  • eaa27c9: [Messenger] never reuse the received AMQP routing key when sending to another transport
  • 4e2e2e1: [Finder] respect .git/info/exclude in ignoreVCSIgnored()
  • 41101af: [Finder] match symlinks against their own path in ignoreVCSIgnored()
  • 37bfedd: [FrameworkBundle, HttpKernel] collect garbage cycles in the callers of Kernel::shutdown()
  • c86a2ec: [Console] fix invalid null device redirection on Windows
  • abbc7f4: [DomCrawler] ignore documents without a root element in addNode()
  • c31777f: [RateLimiter] fix SlidingWindow wait duration when refused by the hits of the current window
  • e6b9585: [RateLimiter] fix early retry and expiry times, and three consume() edge cases
  • 302913c: [HttpClient] fix NativeHttpClient sending paused requests up to one second late
  • cd3e785: [HtmlSanitizer] don't cut a multibyte character when truncating the input to its maximum length
  • b4d3640: [Messenger] do not inherit AMQP expiration when sending to another transport
  • 292d2df: [Messenger] fix the user_id, CC and expiration of republished or delayed AMQP messages
  • 70478b3: [Serializer] fix normalizing a file that DataUriNormalizer denormalized
  • 510c6ba: [BrowserKit] send a Content-Length header when uploading files
  • d779809: [ErrorHandler] log uncaught exceptions like PHP does when no logger is set
  • b65ea19: [ErrorHandler] fix DebugClassLoader suggesting template types as native return types
  • e747d1f: [DependencyInjection] fix env vars reported as never used when overriding an extension service
  • a20291a: [AssetMapper] fix importmap:update and importmap:remove deleting vendor files when they fail
  • b153957: [Config] quote the default values of arrays in the YAML reference
  • 9acc279: [FrameworkBundle] fix describing classes whose docblock only has a tag
  • 46178cd: [Serializer] fix denormalizing a scalar into a union with an object type
  • ea2f56a: [PropertyInfo] fix resolution of self, static and parent in collection types
  • 2e0f9c4: [MonologBridge] fix NotifierHandler not raising levels below Error with Monolog 3
  • 1f81a38: [Notifier, Brevo] update the Brevo API documentation link
  • 2671146: [Mailer] throw a TransportException when proc_open() is not available
  • 0b16a10: [DependencyInjection] fix process() running twice on extensions also registered as compiler passes
  • 2216d51: [String] preserve text after emoji joiners in width calculations
  • f5fb5ea: [FrameworkBundle] fix TestContainer::initialized() for private services
  • f0cf862: [DependencyInjection] fix lazy closures for static and never-returning methods
  • 9569e40: [VarExporter] preserve named variadic arguments in lazy proxies
  • fda494c: [Notifier] fix Transport::fromDsn() when some bridges are installed
  • 2a976fc: [Console] fix StringInput dropping quotes inside a quoted option value
  • 934454e: [Translation] check XLIFF 2 target language when linting filenames
  • 8655302: [String] fix slugger cache changing parent locale transliteration
  • 2bbc710: add PHP 8.7 to CI
  • 2f48c50: [String] fix hyphenated locales in AsciiSlugger
  • b32c65d: [Console] fix shell completion when a global option conflicts with an option of _complete
  • 7b9ef2b: [HttpFoundation] fix cookie names and header parsing
  • 50fbc47: [DependencyInjection] preserve XML schema temporary files in forked processes
  • 7424844: [DomCrawler, HttpKernel, Process, Translation] fix cleanup after forking
  • ef85b7a: [DomCrawler] strip and collapse whitespace in option text used as value
  • 00a3bf1: [DomCrawler] do not submit reset inputs
  • d063ce7: [DomCrawler] skip disabled options when choosing the default value of a select
  • 234de46: [DomCrawler] do not submit fields inside a disabled fieldset
  • 950f19f: [DomCrawler] fix select defaults and disabled options with duplicate values
  • faddd28: [DomCrawler] exclude script text from option values
  • 5526ef2: [Lock] fix database names parsed from MongoDB URIs
  • 416f14b: [Form] reject week numbers lower than 1 in WeekToArrayTransformer

7.4 changelog:

  • af33558: [ObjectMapper] fix losing the value mapped to a promoted property when a later #[Map] is skipped
  • 6c3fb7c: [Console] lock an invokable command on its name alone, not on its aliases
  • 351a5e2: [Console] lock an invokable command on the name of the command that runs it
  • 4157575: [Security] fix TraceableAccessDecisionManager reusing a finished access decision
  • 668cfae: [Runtime] don't terminate the last request twice when a FrankenPHP worker stops
  • f416304: [HtmlSanitizer] ignore meta charset declarations in NativeParser
  • bbee29c: [PropertyInfo] fix resolution of self, static and parent with TypeInfo
  • 0e5f700: [ObjectMapper] remove @internal from Mapping
  • 3db5ea8: [FrameworkBundle, Serializer] fix nested normalizers being shared between named serializers
  • 6219175: [Routing] remove the "deprecated" key from route definitions in routing.schema.json
  • 6ecb7aa: [JsonStreamer] fix reading JSON lists as non-list arrays from streams
  • 11b0250: [JsonStreamer] fix value transformers called on missing properties
  • a7db9dc: [JsonStreamer] fix exponential data model on unions of already generated classes
  • d435eac: [Messenger] release deduplication lock after failed dispatch
  • 4be9c89: [JsonStreamer] fix string validation and non-seekable stream reads
  • 0e36b84: [TypeInfo] resolve keywords case-insensitively in StringTypeResolver
  • 0190596: [JsonStreamer] fix numeric streamed names
  • ee8fc4f: [Cache] fix Relay Cluster node selection when clearing pools

8.1 changelog:

  • 06b66c8: [Serializer] fix denormalizing nested scalar collections from XML
  • 6cb7f4a: [HttpKernel] replace the error handler loggers installed by a previous container
  • bde72c4: [Console] support sections in TestOutput
  • ac1e3f6: [DependencyInjection, VarDumper] import the PHPUnit attributes that some tests use without a use statement
  • 60a6245: [DependencyInjection] fix autowiring intersection types with aliases of aliases
  • b2de538: [Tui] fix widths of newer Unicode characters and emoji
  • 3e66968: [Translation] support the official XLIFF 2.2 namespace
  • 7fe69d8: [JsonStreamer] preserve JSON encoding error messages
  • c1591b9: [Console] preserve temporary input files in forked processes

8.2 changelog:

  • d535454: [ObjectMapper] merge the objects that repeated #[Map] attributes map to the same property
  • 261a87b: [Finder] negate bracket expressions that start with "!" or "^" in glob patterns
  • f7a6a88: [Security, SecurityBundle] add the entry_point_path firewall option
  • 28335d5: [HttpKernel] make compiled expression languages lazy
  • 1c9fe48: [SecurityBundle] make the built-in access token handlers lazy
  • 22307b8: [HttpKernel] filter the loggers of the error handler once instead of on every main request
  • cb904c7: [HttpFoundation] set the bags of requests and responses without reflection
  • 835c707: [DependencyInjection] resolve undefined env vars that have a default without throwing an exception
  • dd3a69a: [FrameworkBundle, HttpKernel] restore the exception handler replaced by DebugHandlersListener when services are reset
  • f1abf38: [HttpFoundation] make Cache-Control directive changes cheaper
  • cb8e4b1: [HttpClient] close idle connections when the kernel shuts down
  • 96e6e22: [Messenger, AmpSql] let the transport reconnect after close()
  • 502e866: [Messenger, Beanstalkd] implement CloseableTransportInterface
  • 9e00995: [Security] log the authenticator support checks in one debug record
  • a8a0cfa: [Messenger] close the transports when the kernel shuts down
  • e9d4f32: [HttpFoundation] don't create the session in Request::hasPreviousSession() when the request has no cookies
  • 4f587e8: [TwigBridge] don't start a new session when reading flash messages
  • e0c5eca: [Security] don't start a new session in AuthenticationUtils
  • 3719f1d: [DependencyInjection] reduce the per-service overhead of ServicesResetter
  • 510645e: [HttpKernel] cache the attributes and argument metadata of controllers
  • e55c9d9: [Security, SecurityBundle] make the OIDC services of oidc_login lazy
  • add1493: [Routing] reset the request context without going through its getters and setters
  • 7e281ed: [SecurityBundle] remove the channel listener when no access control rule requires a channel
  • d4fd72e: [HttpKernel] build the URI logged for the matched route from the request context
  • 380280e: [FrameworkBundle, HttpFoundation] close the lazy Redis connection of the session handler at kernel shutdown
  • ed0ecc7: [Lock] close the connections of lock stores when the kernel shuts down
  • 4e9b323: [Semaphore] close the Redis connection of semaphore stores when the kernel shuts down
  • 3517834: [Mailer] stop the SMTP transports when the kernel shuts down
  • 64c5822: [Cache] close connections when the kernel shuts down
  • 6b7a787: [DependencyInjection, HttpKernel] collect garbage cycles in KernelTestCase and KernelBrowser only when needed
  • 1ace198: [Validator] speed up Unique validation of integers and strings
  • d584d49: [DomCrawler] speed up duplicate node checks for large selections
  • 2a09a0e: [DependencyInjection] speed up collecting service conditionals
  • 9cff1ef: [Finder] speed up sorting by name and extension
  • 16958c8: [OptionsResolver] speed up resolving options
  • 2da7eb3: [TwigBridge] look up form blocks in the block chain without caching them per view
  • 7e4c2af: [Form] skip copying the view variables of blocks rendered without variables
  • 2154245: [Form] share the ICU formatters of the localized string transformers
  • a99af12: [AssetMapper] keep the compiled files in memory once they are read
  • cde052c: [AssetMapper] reuse the rendered import map when its inputs did not change
  • fb0d993: [AssetMapper] reuse the import map data when the compiled files did not change
  • e001e5e: [AssetMapper] preload the classes used at runtime by the import map
  • 5002674: [HttpKernel] share the cached metadata of controllers between instances
  • 1d11b8d: [PropertyInfo] share the read infos of ReflectionExtractor instances that have the same configuration
  • c3ba6af: [ErrorHandler] report attributes whose class does not exist in or below the namespace they are used in
  • 387f024: [RateLimiter] fix RateLimit::getResetAt() being up to one second early
  • 66bc5e6: [ErrorHandler] parse only the docblocks that can lead to a deprecation in DebugClassLoader
  • 37e27be: [Ldap] send only the changed attributes when updating an entry
  • ef38523: improve the descriptions of the types and attributes registered for autoconfiguration
  • 0f1f695: [Form] remember the guesses of FormTypeGuesserChain
  • a68de6e: [TwigBridge] skip the attributes block of rows without row attributes
  • 2119b45: [DependencyInjection, EventDispatcher, Serializer] break the reference cycles of the event dispatcher and the serializers when the kernel shuts down
  • c5445b7: [MonologBridge] allow NotifierHandler to handle records below the Error level
  • 787fb0c: [AssetMapper] keep the mapped assets in memory between requests when debug is off
  • 7b8c9ae: [Console] add suggestPaths() and suggestDirectories() to let the shell complete paths
  • b771f03: [FrameworkBundle, HttpKernel] log fragment errors before rendering the alt URI
  • 4fd91f2: [DomCrawler] make ChoiceFormField::disableValidation() part of the public API
  • 0046233: [HttpKernel, VarDumper] show previous exceptions in the profiler, without the trace frames they share with their wrapper
  • a48e3a1: [ObjectMapper, Serializer, Validator] share immutable metadata between the containers created by kernel resets
  • ef8308a: [Mime] make emails faster to create and serialize
  • 9b5aeab: [FrameworkBundle] set the default locale when a console command starts
  • bf3fe46: [Routing, TwigBundle, FrameworkBundle] add shortcuts for template and redirect routes
  • 29b824d: [String] cache character widths and measure ASCII runs together
  • d7b062a: [Emoji] make EmojiTransliterator faster
  • da59e51: [DependencyInjection] make autowired callables lazy by default
  • 5b06b7c: [HttpFoundation] build parameter keys in a single pass
  • f22780f: [Form] build ordered map keys in a single pass
  • ce50778: [Routing] rely on stable sorting for route priorities
  • 17346c5: [DependencyInjection] rely on stable sorting for the initial priority order
  • 260cc0f: [Console] avoid temporary arrays when checking autocompletion keys
  • a8b848c: [HttpClient] limit read-ahead for active responses
  • a67597e: [TypeInfo] skip specification-based resolution in GenericType::isIdentifiedBy()
  • c06e4e4: [JsonStreamer] inline hydration in string stream readers
  • 3f1f157: [JsonStreamer] buffer writes in generated stream writers
  • 1a9eabc: [JsonStreamer] split streams with a structural scanner
  • f40dd05: [SecurityBundle] add the discovery_uri option to the oidc_login authenticator
  • 4001428: [Cache, Messenger] fix MongoDB database names read from DSNs
  • c5988df: [Console] add %command.invocation% and migrate command examples
  • f987129: [Console, ErrorHandler] adapt Composer hints when using Symfony CLI
  • a25e66f: [JsonStreamer] read stream collection items at once
  • 2b47f84: [KeyManagement] authenticate the context of encrypted Doctrine columns
  • 8fd98cf: [JsonStreamer] skip strings nested in split collection values at once
  • 728a4af: [Cache] fix Relay Cluster node selection when pruning tags

Symfony UX development highlights

3.x changelog:

  • 6d3f44f: [Native] add the historical location navigation
  • e4d1cd3: [Inspector] document how to exclude the script route from the security firewall
  • 1afc7c4: [Toolkit, Shadcn] round the position of the navigation-menu panel to a whole pixel
  • 68a53ac: [Toolkit, Shadcn] make the rich color toasts of Sonner opaque in dark mode
  • 99987d7: [Toolkit, Shadcn] add trace recipe
  • 8e4daf2: [Toolkit, Shadcn] add code-block recipe
  • a353706: [Toolkit, Shadcn] add the missing login, signup and sidebar blocks
  • bae0622: [Toolkit, Shadcn] fix dropdown-menu ignoring align on the left and right sides
  • a29bf7a: [Toolkit, Shadcn] fix the gap of floating and inset sidebars being 16px too wide
  • 0820ef1: [Toolkit, Shadcn] add an as prop to Sidebar:GroupLabel and size nested icons in Sidebar:MenuButton
  • 403d92f: [Toolkit, Shadcn] fix nested and side-by-side sidebars exposing landmarks with the same name
  • a3ce8ef: [Toolkit] fix update_toolkit_tests.sh stopping before the screenshots of a block
  • 4b3d01d: [Toolkit, Shadcn] add message-scroller recipe
  • 3b70573: [LiveComponent] reset deterministic ids without a PostRenderEvent listener
  • a32f553: [LiveComponent] only match children fingerprints against live components
  • 58ae38c: [LiveComponent] sync the value of selects mapped via a form after re-render
  • c80fa84: [LiveComponent] keep the id of a child component with an explicit id when its props change
  • d876039: [LiveComponent] send the queued request after an error response
  • fa23054: [Pagination] support Symfony UID cursor fields
  • 206f346: [LiveComponent] fix disabled choices being submitted by live form updates
  • 39d7709: [TwigComponent] fix pre-lexer only recognizing one spelling of block and embed tags
  • 53ff405: [LiveComponent, TwigComponent] skip live-only and data-model listeners for other components
  • cba45bc: [Toolkit] make the installation directories of recipes configurable

Symfony AI development highlights

Changelog:

  • 0dd0939: [AI Bundle] register alias for argument for all platforms to support #[Target] injection
  • 83b49e5: [Platform, Generic] OpenRouter, prevent duplicate completion of streamed tool calls
  • ba34011: [Store, Postgres] create the vector index with the operator class of the store distance
  • 90bec16: [Store, AzureSearch] read the limit option and run an approximate vector query by default
  • 30c64ab: [AI Bundle, Store, MongoDB] create the vector index with the similarity of the store
  • 90e082a: [Store, MariaDB] parse the query vector once per query
  • 4c20614: [AiBundle] fix non existing parameter issues
  • 4cb4199: [Documentation, Store] fix SQLite, HTTP client and count docs
  • 91f41c7: [AI Bundle] fix profiler failing to serialize nested multi-part results
  • 18400c7: [Store, SurrealDb] remove the table in drop()
  • d4c39dc: [Platform] remove InMemoryPlatform in favor of MockPlatformFactory
  • ceb2cd2: [Platform, Ollama] send image content in Ollama's native message format
  • 69063a4: [Store, MariaDB] require MariaDB 11.8 for Distance::Distance
  • 45f9a39: [Platform] rename the canonical max_output_tokens option to each bridge's own wire field
  • d34fc49: [Store, Weaviate] send the X-Weaviate-Client-Integration header
  • a8be917: support VoyageAI reranking
  • fa0b628: [Platform, HuggingFace] convert tool calls in chat completion results
  • 03fdf93: [Platform, HuggingFace] Follow-up on tool call support
  • f05588b: [Platform, Ollama] add changelog entry for UserMessageNormalizer
  • 382f008: [Documentation, Platform, HuggingFace] document tool calling
  • b055d49: [AI Bundle, Store, S3Vectors] pass setup options to the setup command
  • 4029803: [Platform, HuggingFace] use the unified chat completions endpoint for third-party providers
  • 2a83a31: [Platform, OpenResponses] fix null array offset deprecation on an incomplete response without output
  • 0c0db66: [Platform] avoid filtering callbacks when removing system messages
  • b95c3c8: [Platform, Perplexity] migrate from Sonar Chat Completions to the Agent API
  • 2abf044: [Platform] use loops consistently in MessageBag
  • 69effaf: [AI Bundle, Store, Pinecone] pass setup options to the setup command
  • dcacaa7: [AI Bundle, Agent, Documentation] explain how to notice an MCP server whose tools could not be listed
  • 24dd653: [Platform, OpenResponses] handle unexpected error response bodies
  • 6e1266d: [Store, SurrealDb] authenticate before every request
  • ec01c8d: [Examples] keep the document text for reranking in the retriever examples
  • e48439f: add regression tests for profiler serialization of nested results
  • 5ba5ce1: [Platform, Decision] move the decision types out of the TypeSafe bridge into a Decision bridge
  • b0026fc: [Store, SurrealDb] support SurrealDB 3
  • 3c26bb0: [Platform, HuggingFace] resolve models from the Hub API with a model class per task
  • 98c6333: [AI Bundle] fix MongoDB and SurrealDB message store autowiring aliases
  • 6dd3fe9: [Mate] document symfony-dotenv-check and skills:install --format
  • 40fc767: [MCP Bundle] mention client support in the intro
  • 25dea59: [Docs] fix outdated references
  • 849c877: [Mate] fix flaky Doctrine collector formatter integration test
  • bf075f5: [Agent, Examples] fix outdated example models and Ollama null links
  • 17904b7: bump version constraints to 0.15
  • e0daf44: [Platform, Ollama] support decision models
  • 23dc2eb: [Platform] add CachedModelCatalog and smoother model catalog DX

Symfony CLI

Symfony CLI is a must-have tool when developing Symfony applications on your local machine. It includes the Symfony Local Server, the best way to run local Symfony applications. This week Symfony CLI released its new 5.22.2 version with the following changes:

  • Install the Upsun CLI from upsun/cli and restore hidden cloud command aliases (@fabpot)
  • Restore the upstream hidden aliases of cloud commands like cloud:logs, which the generator was dropping (@fabpot)
  • Read hidden aliases of cloud commands from the upstream command list instead of hardcoding them (@fabpot)
  • Read cloud command aliases from the upstream command list, which also covers commands implemented in Go (@fabpot)
  • Download the Platform.sh/Upsun CLI from upsun/cli as platformsh/cli is archived and stuck at 5.9.0 (@fabpot)

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:

Upcoming Symfony Events

Call to Action

Published in #A week of symfony