innmind/media-type
A PHP library for working with media types (MIME types): parse, validate, and compare content types, handle parameters, and map file extensions. Lightweight and framework-agnostic, it helps Laravel and PHP applications negotiate HTTP responses, validate uploads, and manage content-type headers relia...
Architecture fit. innmind/media-type is a pure domain value object — no I/O, no framework coupling, no service provider, no config. That is exactly the shape of dependency a TPM wants in a Laravel codebase: it can live in app/Domain or a packages/ module without dragging Laravel into the domain or the domain into Laravel. The trade-off is that it is a stringly-typed problem already solved three times over in a typical Laravel stack (symfony/mime, league/mime-type-detection, Illuminate\Http\Testing\MimeType). The package's only defensible advantage is strict RFC 6838 conformance expressed as a typed object (type, subtype, suffix, parameters) rather than as a loose string. If the product does not need to reason about media types — only pass them through — this is a solution looking for a problem.
Integration feasibility. Composer-installable, MIT, PSR-4 — it will drop into a Laravel app with zero wiring beyond an optional container binding. The real cost is cultural, not technical: the Innmind ecosystem is idiomatic functional PHP (innmind/immutable collections, Maybe/Either-style results, strict typing), which is a foreign dialect to a team writing Eloquent and Blade. Expect reviewers to bounce PRs that introduce Sequence/Maybe semantics into a controller path unless the wrapper hides them.
Technical risk. High relative to the value delivered:
TEXT/HTML → text/html), how it handles vendor trees (application/vnd.api+json), quoted parameters (charset="utf-8"), wildcards (*/*, text/*), and obsolescent types is not something I can assert from repo metadata — it must be tested against a real corpus.Maybe determines whether every call site needs a try/catch or an ->match() — a design decision that leaks into controllers.Key questions for the maintainer/spike.
innmind/immutable come along, and at what version?Content-Type headers faithfully including parameter order and quoting?;, mixed case, legacy x- types)?Stack fit. Treat it strictly as a leaf dependency at the edges of the application: inbound Content-Type/Accept negotiation, upload validation, API response metadata, storage object metadata. Do not let it into Eloquent casts or model attributes — a media type is a transport concern, and casting it into persistence couples migrations to a 0-adoption package.
Migration path. Do not adopt it directly. Introduce an internal App\Domain\MediaType (or a MediaTypeParser interface) first, backed today by symfony/mime (already present via Laravel) and league/mime-type-detection. That wrapper gives you the typed API you actually want with a dependency you already ship. Swap the internals to innmind/media-type later only if the wrapper proves insufficient — a two-hour change behind a stable interface rather than a refactor of every call site.
Compatibility. No technical conflict with Illuminate Collections; the friction is purely idiomatic. Check the PHP floor against your runtime matrix before the spike, and check the innmind/immutable constraint against anything else in composer.lock. If your team is on Laravel Pint/PHPStan level 6+, expect the package's functional generics to complicate static analysis at the boundary — keep it behind the wrapper so Psalm/PHPStan only sees your interface.
Sequencing.
symfony/mime. This single artifact answers the permissiveness question that no README will.Accept parsing is where strict RFC conformance buys the most (suffix handling, q-values aside), and blast radius is small.Decision rule for the TPM: adopt directly only if the spike shows it rejects/normalizes cases the incumbent gets wrong and the maintainer answers the error-contract and semver questions. Otherwise the wrapper is the deliverable, and this package is a swap-in candidate behind it.
Maintenance. Footprint is tiny — a handful of classes, no runtime configuration, nothing to patch monthly. The maintenance burden is not in the code but in the ownership gap: no vendor, no security policy, no release notes discipline you can rely on. Budget one engineer-day per year for "check upstream still exists, vendor if not." MIT means you can fork and vendor it into packages/ with a one-line composer change if the maintainer disappears; that is the real insurance policy, and it should be documented in the ADR rather than left implicit.
Support. Effectively zero external support: no docs site of note, no community, no commercial backing. Any incident is debugged by reading the source. This is acceptable for a leaf parser and unacceptable for anything on the critical path of a payment or auth flow. Set expectations with the team accordingly — the on-call runbook entry for "media type parsing bug" should point at your wrapper, not the vendor repo.
Scaling. Non-issue. Pure string parsing, no allocation pressure worth measuring, no network, no cache. At high request volume the only consideration is parsing the same header repeatedly within a request — memoize per request if Accept is inspected in middleware, controller, and serializer. Do not add a cache layer; the complexity would exceed the cost.
Failure modes.
application/octet-stream, log the raw header.innmind/immutable into a stack that will then contain two collection algebras. Mitigation: never expose those types across the wrapper boundary.Ramp-up. Half a day for one engineer to read the package and its tests; a further half-day to become fluent in the Innmind idioms if the codebase is Laravel-native. The genuine ramp cost is onboarding reviewers who will otherwise reject functional-style code in a controller. Keeping the package confined behind an interface reduces that to near zero — which, given 0 stars and 0 dependents, is the correct posture: treat it as an unproven but cheap-to-reverse implementation detail, not an architectural commitment.
How can I help you explore Laravel packages today?