webignition/internet-media-type-interface
PHP interface package defining contracts for representing internet media types (MIME types). Provides a shared API for parsing, validating, and comparing media type strings so implementations can interoperate across the webignition ecosystem.
This package is interfaces only — composer require webignition/internet-media-type-interface gives you contracts, not usable instances. For most Laravel work you also want the concrete implementation (webignition/internet-media-type) or your own class implementing InternetMediaTypeInterface / InternetMediaTypeParserInterface.
Look first at:
InternetMediaTypeInterface — the value object contract (type, subtype, parameters, __toString)ParameterInterface — the parameter contract (name/value)InternetMediaTypeParserInterface / ParameterParserInterface — parsing entry pointsFirst use case: parse the Content-Type of an incoming request and compare it to an expected type in a middleware or form request, instead of string-matching headers by hand.
// AppServiceProvider::register()
$this->app->bind(
\webignition\InternetMediaTypeInterface\InternetMediaTypeParserInterface::class,
\webignition\InternetMediaType\Parser\Parser::class // from the implementation package
);
$mediaType = app(InternetMediaTypeParserInterface::class)->parse($request->header('Content-Type'));
if ($mediaType->getType() === 'application' && $mediaType->getSubtype() === 'json') {
// ...
}
Parse once, reuse everywhere. In a middleware, parse Accept / Content-Type on the way in, attach the resulting media type(s) to the request or to a request-scoped container binding, and let controllers/validators consume them rather than re-parsing strings.
Content negotiation. Split Accept on ,, parse each entry, and sort by the q parameter yourself — the interface has no negotiation logic. This is the natural place to put a small AcceptsJson-style middleware backed by the parser.
Derive, don't mutate (1.0 style). Because setters are now withers, build variants by reassigning:
$withCharset = $mediaType->withParameters(
$mediaType->getParameters()->withParameter(new Parameter('charset', 'utf-8'))
);
Treat every with*() call as returning a new object; keep the original if you need it.
Round-trip through __toString() for response headers. Build the media type once, then cast to string when setting Content-Type on a Response or JsonResponse. This avoids hand-concatenating type/subtype; name=value.
Validate against an allow-list (e.g. application/json, application/vnd.api+json) by comparing normalized type/subtype pairs rather than raw strings — this handles differing parameter order, whitespace, and casing.
Testing. Because these are interfaces, you can bind a fake parser in tests or use the concrete implementation directly for parse-and-assert unit tests; avoid mocking the value object itself.
1.0 is breaking. ParameterInterface no longer has setters, and InternetMediaTypeInterface setters (setType, setSubtype, setParameters, …) were replaced with withers (withType, withSubtype, withParameters, …). Any pre-1.0 code calling setters will fatal — audit before upgrading. This is a semver-major for a reason; pin ^1.0 only when you've migrated.
Forgetting the return value is a silent bug. With withers, $mediaType->withSubtype('json'); does nothing. Static analysis (PHPStan/Psalm with @return static/@return self) catches this cheaply — worth enabling given the interface-only design.
Interface-only binding failures. app(InternetMediaTypeParserInterface::class) throws if you never bound an implementation. Bind it in a service provider and consider singleton since parsers are typically stateless.
Normalization is on you. The interface doesn't guarantee lowercased type/subtype or trimmed values depending on implementation — normalize before comparing, or comparisons will fail on Application/JSON.
Parameter order matters for __toString() equality but usually not for semantic equality. If you're using string comparison as a shortcut for "same media type," sort parameters first or compare structured fields.
q values are parameters too. Don't assume getParameters() only contains content-type parameters; filter q (and any accept-ext) out before using the object as a Content-Type value.
Header access quirks. Laravel's $request->header() returns a string for most headers but can return arrays for multi-value ones; guard against arrays and nulls before handing to the parser, or you'll get confusing parse exceptions rather than a clean 415.
Extension point: implementing InternetMediaTypeInterface yourself is reasonable if you need framework-specific serialization (e.g. a Responsable or a castable attribute), but keep __toString() output RFC-compliant so downstream consumers aren't surprised.
How can I help you explore Laravel packages today?