A simple, request-scoped data container for Laravel
RequestBag provides an easy way to share data between classes during a single request lifecycle without passing parameters around. Perfect for middleware chains, Inertia.js setups, and any scenario where you need to share contextual data across your application.
- π― Request-scoped - Data lives only for the duration of a single request
- π No parameter passing - Share data between classes without cluttering method signatures
- π Type-safe - Built with PHP 8.4+ and strict types
- π¨ Clean API - Simple, intuitive methods that just work
- π§ͺ Fully tested - Comprehensive test coverage with Pest
- β¨ Laravel-friendly - Facade support and automatic service provider registration
Install via Composer:
composer require bensedev/request-bag
The service provider and facade are automatically registered via Laravel's package discovery.
use Bensedev\RequestBag\Facades\RequestBag;
// Add data
RequestBag::add('user_permissions', ['edit', 'delete', 'create']);
RequestBag::add('tenant_id', 123);
// Retrieve data
$permissions = RequestBag::get('user_permissions');
$tenantId = RequestBag::get('tenant_id');
// With default value
$theme = RequestBag::get('theme', 'light');
// Check if key exists and has value
if (RequestBag::has('user_permissions')) {
// Key exists and is not empty
}
// Check if key exists (even if empty)
if (RequestBag::exists('theme')) {
// Key exists
}
Share computed data from middleware with your controllers:
namespace App\Http\Middleware;
use Bensedev\RequestBag\Facades\RequestBag;
use Closure;
class LoadUserPermissions
{
public function handle($request, Closure $next)
{
$permissions = auth()->user()->permissions->pluck('name')->toArray();
// Store in RequestBag instead of adding to request
RequestBag::add('user_permissions', $permissions);
RequestBag::add('is_admin', auth()->user()->isAdmin());
return $next($request);
}
}
Then access it anywhere in your application:
namespace App\Http\Controllers;
use Bensedev\RequestBag\Facades\RequestBag;
class PostController extends Controller
{
public function store()
{
// No need to pass permissions around!
if (RequestBag::has('user_permissions')) {
$permissions = RequestBag::get('user_permissions');
if (in_array('create_post', $permissions)) {
// Create post
}
}
}
}
Share data with your Inertia frontend:
namespace App\Http\Middleware;
use Bensedev\RequestBag\Facades\RequestBag;
use Illuminate\Http\Request;
use Inertia\Middleware;
class HandleInertiaRequests extends Middleware
{
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'auth' => [
'user' => $request->user(),
// Pull from RequestBag populated earlier in middleware chain
'permissions' => RequestBag::get('user_permissions', []),
'is_admin' => RequestBag::get('is_admin', false),
],
'tenant' => [
'id' => RequestBag::get('tenant_id'),
'name' => RequestBag::get('tenant_name'),
],
]);
}
}
Share computed data between services:
namespace App\Services;
use Bensedev\RequestBag\Facades\RequestBag;
class TenantService
{
public function loadTenantContext(int $tenantId): void
{
$tenant = Tenant::with('settings')->find($tenantId);
RequestBag::merge([
'tenant_id' => $tenant->id,
'tenant_name' => $tenant->name,
'tenant_settings' => $tenant->settings->toArray(),
]);
}
}
class InvoiceService
{
public function createInvoice(array $data): Invoice
{
// Access tenant data without dependency injection
$tenantId = RequestBag::get('tenant_id');
$settings = RequestBag::get('tenant_settings');
return Invoice::create([
'tenant_id' => $tenantId,
'currency' => $settings['default_currency'],
// ...
]);
}
}
// Add a single value
RequestBag::add(string $key, mixed $value): self
// Merge multiple values
RequestBag::merge(array $data): self
// Example
RequestBag::add('user_id', 123);
RequestBag::merge(['theme' => 'dark', 'locale' => 'en']);
// Get a value (with optional default)
RequestBag::get(string $key, mixed $default = null): mixed
// Get all data
RequestBag::all(): array
// Example
$userId = RequestBag::get('user_id');
$theme = RequestBag::get('theme', 'light');
$all = RequestBag::all();
// Check if key exists and is not empty
RequestBag::has(string $key): bool
// Check if key exists (even if empty)
RequestBag::exists(string $key): bool
// Example
if (RequestBag::has('user_id')) {
// Key exists and has a value
}
if (RequestBag::exists('theme')) {
// Key exists (might be empty)
}
// Remove a specific key
RequestBag::remove(string $key): self
// Clear all data
RequestBag::clear(): self
// Example
RequestBag::remove('temp_data');
RequestBag::clear();
All methods that modify the bag return self
for fluent chaining:
RequestBag::add('key1', 'value1')
->add('key2', 'value2')
->merge(['key3' => 'value3'])
->remove('key1');
You can also inject the class directly instead of using the facade:
use Bensedev\RequestBag\RequestBag;
class MyService
{
public function __construct(
private RequestBag $bag
) {}
public function doSomething(): void
{
$this->bag->add('key', 'value');
}
}
Run the test suite:
composer test
Run PHPStan:
composer analyse
Run Laravel Pint:
composer format
- PHP 8.4 or higher
- Laravel 12.0 or higher
The MIT License (MIT). Please see License File for more information.
If you discover any issues, please open an issue on GitHub.