chubbyphp / chubbyphp-negotiation
Chubbyphp Negotiation
Package info
github.com/chubbyphp/chubbyphp-negotiation
pkg:composer/chubbyphp/chubbyphp-negotiation
Requires
- php: ^8.3
- psr/http-message: ^1.1|^2.0
Requires (Dev)
- chubbyphp/chubbyphp-container: ^2.5.2
- chubbyphp/chubbyphp-dev-helper: dev-master
- chubbyphp/chubbyphp-http-exception: ^1.3.4
- chubbyphp/chubbyphp-laminas-config-factory: ^1.5.3
- chubbyphp/chubbyphp-mock: ^2.2.2
- infection/infection: ^0.35.4
- php-coveralls/php-coveralls: ^2.9.1
- phpstan/extension-installer: ^1.4.3
- phpstan/phpstan: ^2.2.13
- phpunit/phpunit: ^12.5.34
- pimple/pimple: ^3.6.2
- psr/http-server-middleware: ^1.0.2
Suggests
None
Provides
None
Conflicts
- chubbyphp/chubbyphp-container: <2.4.1 || >=3.0
- chubbyphp/chubbyphp-http-exception: <1.3.2 || >=2.0
- chubbyphp/chubbyphp-laminas-config-factory: <1.5.1 || >=2.0
- pimple/pimple: <3.6.1 || >=4.0
- psr/http-server-middleware: <1.0.2|| >=2.0
Replaces
None
README
Description
A small, dependency-light content negotiation library for PSR-7 requests.
It picks the best match between what the client asks for and what your application supports:
Accept→ which media type to respond withAccept-Language→ which locale to respond inContent-Type→ whether the request body can be parsed
Each negotiator returns a NegotiatedValue (the matched value plus its header attributes such as q or charset),
or null when nothing matches. Optional PSR-15 middlewares turn a failed negotiation into a 406 Not Acceptable
or 415 Unsupported Media Type response and expose the negotiated value as a request attribute.
Requirements
- php: ^8.3
- psr/http-message: ^1.1|^2.0
Suggest
- chubbyphp/chubbyphp-container: ^2.5.2 (for
NegotiationServiceFactory) - chubbyphp/chubbyphp-http-exception: ^1.3.4 (required by the middlewares)
- chubbyphp/chubbyphp-laminas-config-factory: ^1.5.3 (for the laminas-style
ServiceFactoryclasses) - pimple/pimple: ^3.6.2 (for
NegotiationServiceProvider) - psr/http-server-middleware: ^1.0.2 (required by the middlewares)
Installation
Through Composer as chubbyphp/chubbyphp-negotiation.
composer require chubbyphp/chubbyphp-negotiation "^2.3"
Usage
All negotiators share the same contract: pass the supported values to the constructor, call negotiate($request)
and receive a NegotiatedValueInterface (value + header attributes) or null when nothing matches.
The middlewares wrap a negotiator, store the result as a request attribute and throw an HttpException on failure.
Each section below shows the minimal call; the linked page documents the matching rules, edge cases and error data.
AcceptLanguageNegotiator
Negotiates Accept-Language. Exact locale first, then the language of a regional locale (en-US → en), then *.
Full documentation
$negotiator = new AcceptLanguageNegotiator(['en', 'de']); $value = $negotiator->negotiate($request); // 'Accept-Language: de,en-US;q=0.7,en;q=0.3' $value->getValue(); // 'de' $value->getAttributes(); // ['q' => '1.0']
AcceptLanguageMiddleware
Stores the negotiated locale in the request attribute acceptLanguage, or throws 406 Not Acceptable.
Full documentation
$middleware = new AcceptLanguageMiddleware(new AcceptLanguageNegotiator(['en', 'de'])); $response = $middleware->process($request, $handler); // $request->getAttribute('acceptLanguage') inside $handler
AcceptNegotiator
Negotiates Accept. Exact media type first, then structured suffix (+json), then type/*, then */*.
Full documentation
$negotiator = new AcceptNegotiator(['application/json', 'application/xml', 'application/x-yaml']); $value = $negotiator->negotiate($request); // 'Accept: text/html,application/xml;q=0.9,*/*;q=0.8' $value->getValue(); // 'application/xml' $value->getAttributes(); // ['q' => '0.9']
AcceptMiddleware
Stores the negotiated media type in the request attribute accept, or throws 406 Not Acceptable.
Full documentation
$middleware = new AcceptMiddleware(new AcceptNegotiator(['application/json', 'application/xml'])); $response = $middleware->process($request, $handler); // $request->getAttribute('accept') inside $handler
ContentTypeNegotiator
Negotiates Content-Type. Exact media type first, then structured suffix (application/vnd.api+json → application/json).
Header parameters such as charset are returned as attributes.
Full documentation
$negotiator = new ContentTypeNegotiator(['application/json', 'application/xml', 'application/x-yaml']); $value = $negotiator->negotiate($request); // 'Content-Type: application/xml; charset=UTF-8' $value->getValue(); // 'application/xml' $value->getAttributes(); // ['charset' => 'UTF-8']
ContentTypeMiddleware
Stores the negotiated media type in the request attribute contentType, or throws 415 Unsupported Media Type.
Full documentation
$middleware = new ContentTypeMiddleware(new ContentTypeNegotiator(['application/json', 'application/xml'])); $response = $middleware->process($request, $handler); // $request->getAttribute('contentType') inside $handler
NegotiationServiceFactory
Registers all negotiators and middlewares in a chubbyphp/chubbyphp-container under negotiator.* ids.
The supported values are read from negotiator.*.values services, which default to [].
Full documentation
$container = new Container(); $container->factories((new NegotiationServiceFactory())()); $container->factory('negotiator.acceptNegotiator.values', static fn (): array => ['application/json']); $container->get('negotiator.acceptMiddleware')->process($request, $handler);
NegotiationServiceProvider
Registers the same services in a Pimple container, using the same service ids. Full documentation
$container = new Container(); $container->register(new NegotiationServiceProvider()); $container['negotiator.acceptNegotiator.values'] = ['application/json']; $container['negotiator.acceptMiddleware']->process($request, $handler);
ServiceFactory
Invokable factories built on chubbyphp/chubbyphp-laminas-config-factory for
laminas-servicemanager style containers. Each factory can be used unnamed or with a name
([Factory::class, 'name']) to register several independent instances.
- AcceptLanguageMiddlewareFactory
- AcceptLanguageNegotiatorFactory
- AcceptMiddlewareFactory
- AcceptNegotiatorFactory
- ContentTypeMiddlewareFactory
- ContentTypeNegotiatorFactory
Copyright
2026 Dominik Zogg