Installation
composer require chill-project/activity
Ensure your project uses Symfony Flex auto-configuration (Laravel 5.5+) or manually register the bundle in config/app.php under providers.
Publish Configuration
php artisan vendor:publish --provider="Chill\ActivityBundle\ActivityBundle" --tag="config"
This generates config/activity.php. Review and adjust default settings (e.g., activity_model, activity_table).
First Activity Log
Inject the ActivityManager service into a controller or service:
use Chill\ActivityBundle\Manager\ActivityManager;
public function __construct(private ActivityManager $activityManager) {}
public function logExample() {
$this->activityManager->log('user.created', 'User #123 was created', ['user_id' => 123]);
}
Verify
Check the database table (default: activities) for the logged entry.
config/activity.php (adjust table names, models, or logging behavior).src/Manager/ActivityManager.php (core logging interface).src/Entity/Activity.php (customize if extending the default model).Basic Logging
$this->activityManager->log(
'event.name', // Event name (string)
'Human-readable text', // Description
['metadata' => 'value'] // Optional associative array
);
user.login.failed, order.paid).Bulk Logging For batch operations (e.g., importing users):
$this->activityManager->logBulk([
['event' => 'user.imported', 'description' => 'Imported 100 users', 'data' => [...]],
// ... more entries
]);
Conditional Logging Use middleware or decorators to filter activities:
if ($user->isAdmin()) {
$this->activityManager->log('admin.action', 'Performed X', ['user_id' => $user->id]);
}
Laravel-Specific
AppServiceProvider:
$this->app->bind(ActivityManager::class, function ($app) {
return new CustomActivityManager($app->make(ActivityRepository::class));
});
use Illuminate\Auth\Events\Registered;
Registered::listen(function ($event) {
$event->user->activity()->log('user.registered');
});
Database Optimization
event, description, and data columns for queries:
Schema::table('activities', function (Blueprint $table) {
$table->index('event');
$table->index('created_at');
});
API Responses Expose activities via API:
Route::get('/activities', function (ActivityManager $manager) {
return response()->json($manager->findAll()->toArray());
});
Frontend Integration
Performance
logBulk call. Batch in chunks of 100–500.$this->activityManager->logQueued('event.name', 'Description');
Data Serialization
data field is JSON-encoded. Ensure all values are serializable (avoid closures, resources).json_encode($data, JSON_THROW_ON_ERROR) to catch non-serializable data early.Model Customization
Activity model, override fillable to control which fields can be mass-assigned:
protected $fillable = ['event', 'description', 'data', 'metadata'];
Event Collisions
invoice.created vs. created).Missing Logs
Activity model/table exists and is properly configured in config/activity.php.ActivityManager is bound correctly (no service provider conflicts).Query Issues
Activity::query()->toSql() to inspect generated queries.APP_DEBUG=true) to see raw SQL.Data Corruption
data field may corrupt if non-serializable data is passed. Validate inputs:
try {
json_encode($data);
} catch (JsonException $e) {
throw new \InvalidArgumentException('Activity data must be JSON-serializable');
}
Custom Activity Types
Extend the Activity model to add fields:
class CustomActivity extends Activity
{
protected $casts = [
'ip_address' => 'string',
'user_agent' => 'text',
];
}
Update the migration and config accordingly.
Activity Filters
Add scopes to the Activity model for common queries:
public function scopeForUser($query, $userId)
{
return $query->whereJsonContains('data->user_id', $userId);
}
Activity Subscribers Listen for activity events to trigger side effects:
Activity::created(function ($activity) {
if ($activity->event === 'user.suspended') {
// Send email, revoke API keys, etc.
}
});
Testing
Mock the ActivityManager in tests:
$mockManager = Mockery::mock(ActivityManager::class);
$mockManager->shouldReceive('log')
->once()
->with('test.event', 'Test description', ['key' => 'value']);
$this->app->instance(ActivityManager::class, $mockManager);
How can I help you explore Laravel packages today?