macpaw / schema-context-bundle
A Symfony bundle to provide schema context
Installs: 23 574
Dependents: 2
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/macpaw/schema-context-bundle
Requires
- php: >=8.3
- symfony/config: ^6.4 || ^7.0
- symfony/dependency-injection: ^6.4 || ^7.0
- symfony/http-client: ^6.4 || ^7.0
- symfony/http-kernel: ^6.4 || ^7.0
- symfony/messenger: ^6.4 || ^7.0
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
- squizlabs/php_codesniffer: 3.7.*
Suggests
- symfony/doctrine-messenger: Allow use doctrine as messenger transport
README
The SchemaContextBundle provides a robust way to manage dynamic schema context across your Symfony application, especially useful for multi-tenant setups. It extracts schema information from W3C standard baggage headers (or Symfony Messenger Stamps), validates schema changes based on environment configuration, and propagates schema context throughout your application, including HTTP clients and Symfony Messenger queues.
Features
- Extracts tenant schema param from W3C standard
baggagerequest header. - Stores schema and baggage context in a global
BaggageSchemaResolver. - Validates schema changes based on environment configuration to prevent accidental schema mismatches.
- Injects schema and baggage info into Messenger messages via a middleware.
- Rehydrates schema and baggage on message consumption via a middleware.
- Provide decorator for Http clients to propagate baggage header.
- Optional: Adds baggage context to Monolog log records via a processor.
Installation
composer require macpaw/schema-context-bundle
If you are not using Symfony Flex, register the bundle manually:
// config/bundles.php return [ Macpaw\SchemaContextBundle\SchemaContextBundle::class => ['all' => true], ];
Configuration
1. Bundle Configuration
Add this config to config/packages/schema_context.yaml:
schema_context: environment_name: '%env(APP_ENV)%' # Current environment name (example: 'develop') header_name: 'X-Tenant' # Key name in baggage header to extract schema name environment_schema: '%env(ENVIRONMENT_SCHEMA)%' # The schema for this environment (example: 'public') overridable_environments: ['develop', 'staging', 'test'] # Environments where schema can be overridden via baggage header or Symfony Messenger stamp
Configuration parameters:
environment_name: The name of the current environment. Best practice is to use'%env(APP_ENV)%'to match Symfony's environment.environment_schema: The schema for this environment.header_name: The key name in the baggage header used to extract the schema value.overridable_environments: List of environment names where schema can be overridden via baggage header or Symfony Messenger stamp.
APP_ENV=develop ENVIRONMENT_SCHEMA=public
3. Schema Override Protection
The bundle includes protection against accidental schema changes in production environments:
- In non-overridable environments (e.g.,
production): The schema is always fixed toenvironment_schema. Any attempt to override it via baggage header will throwEnvironmentSchemaMismatchException. - In overridable environments (e.g.,
develop,staging): The schema can be dynamically changed via baggage header for testing and development purposes.
Usage
use Macpaw\SchemaContextBundle\Service\BaggageSchemaResolver; public function index(BaggageSchemaResolver $schemaResolver) { $schema = $schemaResolver->getSchema(); $baggage = $schemaResolver->getBaggage(); // Use schema in logic }
Baggage Header Format
The bundle uses W3C standard baggage header format. Example request:
GET /api/endpoint HTTP/1.1 Host: example.com baggage: X-Tenant=tenant_a,user-id=12345,trace-id=abc123
The bundle will extract the schema value from the baggage header using the key specified in header_name configuration.
Exception Handling
EnvironmentSchemaMismatchException
The bundle throws EnvironmentSchemaMismatchException when:
- The environment is not in the
overridable_environmentslist - A request tries to set a schema via baggage header that differs from
environment_schema
This exception prevents accidental schema changes in production/staging/etc. environments. Example error message:
Schema mismatch in "production" environment: expected "public", got "tenant_a". Allowed override environments: [develop, staging, test].
How to handle:
- In production/staging/etc.: ensure clients don't send schema baggage headers, or send the correct environment schema
- In development: add your environment to
overridable_environmentslist if you need to test different schemas
Baggage-Aware HTTP Client
Decorate your http client in your service configuration:
services: baggage_aware_payment_http_client: class: Macpaw\SchemaContextBundle\HttpClient\BaggageAwareHttpClient decorates: payment_http_client #http client to decorate arguments: - '@baggage_aware_payment_http_client.inner'
A Note on Testing
If you are replacing or mocking HTTP clients in your test environment, for example, using a library like macpaw/extended-mock-http-client, you need to disable the BaggageAwareHttpClient decoration.
when@test: services: baggage_aware_payment_http_client: class: Macpaw\SchemaContextBundle\HttpClient\BaggageAwareHttpClient
Messenger Integration
The bundle provides a middleware that automatically:
- Adds a BaggageSchemaStamp to dispatched messages
- Restores the schema and baggage context on message handling
Enable the middleware in your messenger.yaml:
framework: messenger: buses: messenger.bus.default: middleware: - Macpaw\SchemaContextBundle\Messenger\Middleware\BaggageSchemaMiddleware
Optional: Monolog Integration
The bundle provides an optional processor that automatically adds baggage context to your log records:
- Adds baggage information to the
extrafield of log records
To enable the processor, add it to your service configuration:
services: Macpaw\SchemaContextBundle\Monolog\BaggageProcessor: tags: - { name: monolog.processor }
Testing
To run tests:
vendor/bin/phpunit
Contributing
Feel free to open issues and submit pull requests.
License
This bundle is released under the MIT license.