netmex/request-bundle
Netmex Request Bundle helps structure and handle incoming HTTP requests in PHP applications. It provides reusable request objects, validation, and clean controller integration, reducing boilerplate and keeping request logic organized and consistent.
Install with Composer:
composer require netmex/request-bundle
The package is auto-discovered on Laravel 9+; no manual provider registration should be necessary. If a config file is published, run php artisan vendor:publish and check config/request-bundle.php (or similarly named) before writing any code — defaults for pagination size and cache behaviour matter.
Read the README usage section first: https://github.com/netmexmedia/RequestBundle?tab=readme-ov-file#usage. It is the only authoritative reference for the public API; the release notes themselves are terse and do not document signatures.
First use case: an index endpoint for a resource. Build a query from the incoming request, let the bundle apply ordering and pagination, and return a JSON resource collection. Start with a single model (e.g. Post), one filter, one sortable field, and page size 15 — confirm the response shape before adding the cached paginator.
Verify the PHP version constraint in composer.json before adopting. The 2.2.x line introduces attribute-based ordering, which requires PHP 8.0+ and will not degrade gracefully on older runtimes.
Attribute-driven ordering (new in 2.2.x). Declare which model properties are sortable with the OrderBy attribute rather than validating an ad-hoc ?sort= string in each controller. This centralises the allow-list on the model and keeps controllers thin:
class Post extends Model
{
#[OrderBy]
public string $title;
#[OrderBy]
public string $created_at;
}
Confirm the exact attribute class name and namespace from the README — the release notes only say "Added OrderBy attributes" and the FQCN is not stated. Keep the attribute set on the model small and intentional; it is the whitelist that protects against arbitrary ORDER BY injection.
Cached paginator for read-heavy index pages. The second 2.2.x feature. Wrap the paginated result rather than caching the whole response, so the paginator metadata (total, per_page, last_page) stays consistent with the cached page payload. A typical controller:
public function index(IndexPostsRequest $request)
{
$posts = Post::query()
->filtered($request->validated())
->ordered($request);
return PostResource::collection(
$this->paginator->remember($request)->paginate($posts)
);
}
Treat the method names above as illustrative; map them onto the actual package API.
Request object per endpoint. Rather than one global "request bundle" config, define a request/DTO per index endpoint that declares its own filters and its own allowed sorts. This scales better than a shared config block and makes caching keys per-endpoint explicit.
Pair attributes with FormRequests. Attribute ordering handles which columns can be sorted; a FormRequest should still handle which values are valid for filters and the page/per_page bounds. Don't let the attribute layer become your only validation.
Upgrade path. 2.1.0 → 2.2.2 is additive: two new features, no removals or renames listed. The version jump skips 2.2.0 and 2.2.1, so include a patch review of the full changelog diff before deploying. Treat the adoption as low risk but still run the test suite and exercise one index endpoint manually in staging, particularly if you have existing manual orderBy() calls that could now collide with attribute-declared ordering.
Cache invalidation is the main risk with the cached paginator. The cache key must incorporate every input that changes the result set: the full validated query string (filters, sort column, sort direction, page, per_page), plus tenant/team ID and anything auth-scoped. Omitting any of these leaks one user's page into another's response — a serious and easy-to-miss bug. Audit the key construction before shipping, and clear the cache in model observers on write if you need near-real-time listings.
Cache + paginator drift. If you cache the paginator object itself, serialise/deserialise issues and stale total counts are common. Prefer caching the underlying result set or the transformed collection, and rebuild the paginator around it.
OrderBy attribute discovery. PHP attribute discovery relies on reflection over typed properties or declared methods. If a sortable field silently stops working, check that the attribute is on the right target (property vs. method) and that the property is typed — untyped or mixed properties are a frequent cause of missed discovery. Also run php artisan optimize:clear after editing model attributes; cached class maps can mask changes.
Whitelist discipline. Never fall back to orderBy($request->input('sort')) when the attribute lookup misses. Fail closed — reject unknown sort keys with a 422 rather than defaulting to raw input.
Config caching. If you publish a config file, remember php artisan config:cache in deployment. A config read once at boot will not pick up edits made during a long-running Octane/Swoole worker.
Debugging ordering. Dump the compiled SQL (->toSql() plus ->getBindings()) at the point just before pagination. Most ordering bugs are "the attribute wasn't registered" or "a model scope applied its own orderBy afterwards and overrode it."
Extension points. If the built-in filters/orderers don't cover a case, look for a base filter/orderer class or a service-container binding in the README before forking. Wrapping the package behind your own thin service class (one method per concern: filter, sort, paginate) keeps you insulated from minor-version API changes — worth doing given the package is pre-3.x and shipping features quickly.
Documentation gap. The release notes are minimal and there is no published API reference beyond the README. Pin the version in composer.json ("^2.2" rather than "*") and keep an upgrade test that hits one real index endpoint, so a future 2.3.0 change surfaces in CI rather than in production.
How can I help you explore Laravel packages today?