juniorfontenele / laravel-app-context
Context on steroids for Laravel applications
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/juniorfontenele/laravel-app-context
Requires
- php: ^8.4
- illuminate/contracts: ^12
- illuminate/support: ^12
Requires (Dev)
- driftingly/rector-laravel: ^2.1
- larastan/larastan: ^3.0
- laravel/pint: ^1.27
- laravel/prompts: ^0.3.9
- orchestra/testbench: ^10.8
- pestphp/pest: ^4.3
This package is auto-updated.
Last update: 2026-01-28 20:44:28 UTC
README
A powerful and extensible package for managing application context in Laravel. Automatically collect and distribute context information from multiple sources (user, request, environment, etc.) to various channels (logs, monitoring systems, etc.).
Features
- Automatic Context Collection: Built-in providers for timestamp, app info, host info, request data, and user information
- Smart Caching: Intelligent per-provider caching - static context is cached for performance, dynamic context (user, request) is always fresh
- Extensible Architecture: Easy to create custom providers and channels
- Conditional Execution: Providers can determine when they should run
- Multiple Channels: Register context in different systems (logs, monitoring, etc.)
- Facade Support: Clean and elegant API using Laravel facades
- Configuration-Based: Manage providers and channels through a simple config file
- Performance Optimized: Selective caching ensures optimal performance without stale data
Installation
You can install the package via composer:
composer require juniorfontenele/laravel-app-context
The package will automatically register its service provider.
Configuration
Publish the configuration file:
php artisan vendor:publish --tag="laravel-app-context-config"
This will create a config/app-context.php file with the following structure:
return [ 'enabled' => env('LARAVEL_APP_CONTEXT_ENABLED', true), 'providers' => [ // Built-in providers JuniorFontenele\LaravelAppContext\Providers\TimestampProvider::class, JuniorFontenele\LaravelAppContext\Providers\AppProvider::class, JuniorFontenele\LaravelAppContext\Providers\HostProvider::class, JuniorFontenele\LaravelAppContext\Providers\RequestProvider::class, JuniorFontenele\LaravelAppContext\Providers\UserProvider::class, ], 'channels' => [ JuniorFontenele\LaravelAppContext\Channels\LogChannel::class, // Add your custom channels here ], ];
Basic Usage
Using the Facade
use JuniorFontenele\LaravelAppContext\Facades\AppContext; // Get all context $context = AppContext::all(); // Get a specific context value $userId = AppContext::get('user.id'); $appName = AppContext::get('app.name'); // Get with a default value $userName = AppContext::get('user.name', 'Guest'); // Check if a key exists if (AppContext::has('user.id')) { // User is authenticated } // Set a custom value AppContext::set('custom.key', 'custom value'); // Rebuild context from scratch (clears all caches and rebuilds) AppContext::rebuild(); // Clear cache for a specific provider use JuniorFontenele\LaravelAppContext\Providers\TimestampProvider; AppContext::clearProviderCache(TimestampProvider::class); // Clear the context and cache AppContext::clear(); // Reset context and notify channels with empty context AppContext::reset();
Context Structure
The default context includes:
[
'timestamp' => '2024-01-21T10:30:00+00:00',
'app' => [
'name' => 'Laravel',
'env' => 'production',
'debug' => false,
'url' => 'https://example.com',
'timezone' => 'UTC',
'locale' => 'en',
'origin' => 'web', // or 'console'
],
'host' => [
'name' => 'server-01',
'ip' => '192.168.1.100',
],
'request' => [ // Only available in web requests
'ip' => '192.168.1.1',
'method' => 'GET',
'url' => 'https://example.com/api/users',
'host' => 'example.com',
'scheme' => 'https',
'locale' => 'en',
'referer' => 'https://example.com',
'user_agent' => 'Mozilla/5.0...',
'accept_language' => 'en-US,en;q=0.9',
],
'user' => [ // Only when authenticated (always up-to-date)
'id' => 1,
'name' => 'John Doe',
'email' => 'john@example.com',
],
]
Note: User, request and timestamp contexts are always fresh and automatically updated when authentication state or request data changes. Static contexts (app, host) are cached for optimal performance.
Smart Caching System
The package uses an intelligent per-provider caching system:
Cacheable Providers (Static Context)
Providers that return static data are cached for optimal performance:
AppProvider- Application configuration doesn't changeHostProvider- Host information is static
These providers execute once per request and their results are cached.
Dynamic Providers (Always Fresh)
Providers with dynamic data are never cached and always recalculated:
TimestampProvider- Timestamp can change during request lifecycleUserProvider- Authentication state can change (login/logout)RequestProvider- Request data can be modified by middlewares
These providers execute every time you access the context, ensuring data is always up-to-date.
Example: Login/Logout Scenario
use JuniorFontenele\LaravelAppContext\Facades\AppContext; use Illuminate\Support\Facades\Auth; // Before login $context = AppContext::all(); // Result: no 'user' key (not authenticated) // User logs in Auth::login($user); // After login - NO need to call refresh()! $context = AppContext::all(); // Result: 'user' key is present with fresh data // 'app' and 'host' are from cache (fast!)
No manual cache management needed! The context stays fresh where it matters while maintaining optimal performance.
Creating Custom Providers
Providers are classes that collect specific context information. Create a custom provider by implementing the ContextProvider interface or extending AbstractProvider:
Basic Provider (Cacheable)
<?php namespace App\Context\Providers; use JuniorFontenele\LaravelAppContext\Providers\AbstractProvider; class CustomProvider extends AbstractProvider { // isCacheable() returns true by default (from AbstractProvider) // This means the context will be calculated once and cached public function getContext(): array { return [ 'custom' => [ 'key' => 'value', 'data' => $this->getCustomData(), ], ]; } private function getCustomData(): array { return [ 'foo' => 'bar', ]; } }
Dynamic Provider (Non-Cacheable)
For providers with dynamic data that should always be recalculated:
<?php namespace App\Context\Providers; use JuniorFontenele\LaravelAppContext\Providers\AbstractProvider; class SessionProvider extends AbstractProvider { /** * Session data can change during the request, * so it should not be cached */ public function isCacheable(): bool { return false; // Always recalculate } public function shouldRun(): bool { return session()->isStarted(); } public function getContext(): array { return [ 'session' => [ 'id' => session()->getId(), 'cart_items_count' => count(session()->get('cart', [])), ], ]; } }
Choosing Between Cacheable and Non-Cacheable
Use cacheable (default) when:
- ✅ Data is static during the request lifecycle
- ✅ Data comes from configuration files
- ✅ Expensive operations that should run once
- ✅ Environment or system information
Use non-cacheable when:
- ❌ Data depends on authentication state
- ❌ Data can be modified during the request
- ❌ Data comes from sessions or request
- ❌ Data changes based on middleware execution
Conditional Provider
Control when your provider should run using the shouldRun() method:
<?php namespace App\Context\Providers; use JuniorFontenele\LaravelAppContext\Providers\AbstractProvider; class DatabaseProvider extends AbstractProvider { public function shouldRun(): bool { // Only run if database is connected try { \DB::connection()->getPdo(); return true; } catch (\Exception $e) { return false; } } public function getContext(): array { return [ 'database' => [ 'connection' => config('database.default'), 'name' => config('database.connections.' . config('database.default') . '.database'), ], ]; } }
Registering Custom Providers
Add your custom provider to the config/app-context.php file:
'providers' => [ // Built-in providers JuniorFontenele\LaravelAppContext\Providers\TimestampProvider::class, JuniorFontenele\LaravelAppContext\Providers\AppProvider::class, // Your custom providers App\Context\Providers\CustomProvider::class, App\Context\Providers\DatabaseProvider::class, ],
Or register programmatically in a service provider:
use JuniorFontenele\LaravelAppContext\Facades\AppContext; use App\Context\Providers\CustomProvider; public function boot() { AppContext::addProvider(new CustomProvider()); }
Creating Custom Channels
Channels receive the resolved context and register it in different systems (logs, error tracking, etc.). They don't dispatch the context immediately, but rather add it to systems that will use it later. Create a custom channel by implementing the ContextChannel interface:
Basic Channel
<?php namespace App\Context\Channels; use JuniorFontenele\LaravelAppContext\Contracts\ContextChannel; use Illuminate\Support\Facades\Cache; class CacheChannel implements ContextChannel { public function registerContext(array $context): void { // Register context in cache for later use Cache::put('app.context', $context, now()->addMinutes(5)); } }
Advanced Channel Example
<?php namespace App\Context\Channels; use JuniorFontenele\LaravelAppContext\Contracts\ContextChannel; use Sentry\State\Scope; class SentryChannel implements ContextChannel { public function registerContext(array $context): void { // Register context in Sentry for error tracking // This context will be included in all Sentry error reports \Sentry\configureScope(function (Scope $scope) use ($context) { $scope->setContext('app', $context['app'] ?? []); $scope->setContext('host', $context['host'] ?? []); $scope->setContext('request', $context['request'] ?? []); if (isset($context['user'])) { $scope->setUser([ 'id' => $context['user']['id'], 'email' => $context['user']['email'], 'username' => $context['user']['name'], ]); } }); } }
Registering Custom Channels
Add your custom channel to the config/app-context.php file:
'channels' => [ // Built-in channels JuniorFontenele\LaravelAppContext\Channels\LogChannel::class, // Add your custom channels here App\Context\Channels\SentryChannel::class, App\Context\Channels\CacheChannel::class, ],
Or register programmatically:
use JuniorFontenele\LaravelAppContext\Facades\AppContext; use App\Context\Channels\SentryChannel; public function boot() { AppContext::addChannel(new SentryChannel()); }
API Reference
Core Methods
use JuniorFontenele\LaravelAppContext\Facades\AppContext; // Get all context AppContext::all(): array // Get a specific value AppContext::get(string $key, mixed $default = null): mixed // Check if a key exists AppContext::has(string $key): bool // Set a custom value AppContext::set(string $key, mixed $value): self // Rebuild context from scratch (clears all caches) AppContext::rebuild(): self // Clear cache for specific provider AppContext::clearProviderCache(string $providerClass): self // Clear all context and cache AppContext::clear(): self // Reset context and notify channels AppContext::reset(): self // Add provider programmatically AppContext::addProvider(ContextProvider $provider): self // Add channel programmatically AppContext::addChannel(ContextChannel $channel): self
When to Use Each Method
all() and get()
Use for normal context access. These methods are optimized with smart caching.
has()
Use to check if a context key exists before accessing it:
if (AppContext::has('user.email')) { $email = AppContext::get('user.email'); }
rebuild()
Clears all caches and rebuilds the context from scratch. Use when:
- Static configuration has changed and cache needs invalidation
- You need to force complete recalculation for testing
- After significant state changes (e.g., tenant switching in multi-tenancy)
// Example: After changing tenant in multi-tenancy Tenant::switch($newTenant); AppContext::rebuild(); // Example: In testing when you need fresh context AppContext::rebuild();
reset()
Clears all context and notifies channels with empty context. Use when:
- You need to completely reset the context state
- Testing scenarios where you need clean state
- End of lifecycle operations
// Example: In test teardown AppContext::reset();
clearProviderCache()
For granular cache control when you know only specific provider needs refresh:
use JuniorFontenele\LaravelAppContext\Providers\TimestampProvider; // Only recalculate timestamp on next access AppContext::clearProviderCache(TimestampProvider::class);
Built-in Providers
TimestampProvider
Adds the current timestamp to the context.
- Cacheable: ❌ No (timestamp can change during request lifecycle)
AppProvider
Collects application information (name, environment, debug mode, URL, timezone, locale, origin).
- Cacheable: ✅ Yes (application configuration is static)
HostProvider
Collects host information (hostname and IP address).
- Cacheable: ✅ Yes (host information doesn't change)
RequestProvider
Collects HTTP request information (only runs for web requests).
- Cacheable: ❌ No (request data can be modified by middlewares)
UserProvider
Collects authenticated user information (only runs when a user is authenticated).
- Cacheable: ❌ No (authentication state can change during request)
Built-in Channels
LogChannel
Registers context in Laravel's Context system (available since Laravel 11), making it automatically available in all application logs. The context is added using Context::add() and will be included in every log entry.
Environment Variables
Control the package behavior with these environment variables:
# Enable/disable the package LARAVEL_APP_CONTEXT_ENABLED=true
Use Cases
- Enhanced Logging: Automatically add rich context to all your logs through Laravel's Context system
- Debugging: Track request flow with complete context information available in every log entry
- Error Tracking: Register context in Sentry or similar services to get detailed error reports with always-fresh user data
- Performance Monitoring: Add context to APM tools for better performance insights
- Auditing: Track user actions with complete environmental context, automatically updated on authentication changes
- Multi-tenancy: Context automatically stays in sync as users switch between tenants
Testing
composer test
Credits
License
The MIT License (MIT). Please see License File for more information.