ConnectionInterface aligns seamlessly with Laravel’s service container and dependency injection principles. This allows for non-invasive profiling without modifying Rowcast’s core or Laravel’s query builder. The pattern is particularly well-suited for cross-cutting concerns like logging, monitoring, and profiling, which are common in Laravel applications.beberlei/doctrineextensions or spatie/laravel-query-logger may be more appropriate.QueryProfileStore interface enables custom storage backends (e.g., database, Redis, or even external APIs). This is a best practice for scalability and observability but requires upfront planning for production-grade implementations. Laravel’s event system or queue workers could further extend this for async processing.Connection with ConnectionProfiler.QueryProfileStore (default: in-memory).slowQueryThresholdMs).
This aligns with Laravel’s configuration-driven approach, where behavior can be toggled via environment variables or config files.$this->app->singleton(AsceticSoft\Rowcast\ConnectionInterface::class, function ($app) {
$inner = new AsceticSoft\Rowcast\Connection(config('database.connections.rowcast'));
$profiler = new RowcastProfiler(
new DatabaseQueryProfileStore(),
new DefaultParameterSanitizer(),
slowQueryThresholdMs: (float) config('rowcast.profiler.threshold')
);
return new ConnectionProfiler($inner, $profiler);
});
This approach ensures singleton consistency and environment-aware configuration.ConnectionInterface, ParameterBag), the package’s Symfony compatibility is non-disruptive. The RowcastBundle integration further simplifies adoption for projects already using Symfony’s dependency injection.DefaultParameterSanitizer masks sensitive data but may obfuscate debuggable information. Mitigation: Customize sanitization rules (e.g., log hashes of sensitive fields) or use a toggleable sanitizer for development vs. production.InMemoryQueryProfileStore is ephemeral and non-thread-safe. Mitigation: Implement a database-backed store (e.g., using Laravel’s query builder) or Redis for persistence and scalability.App\Exceptions\Handler or log errors to a dedicated table.ConnectionInterface, ParameterBag), the package’s Symfony compatibility is seamless. The RowcastBundle integration further simplifies adoption for projects using Symfony’s dependency injection.QueryProfileStore can push metrics to Prometheus, Datadog, or New Relic.InMemoryQueryProfileStore for testing.$this->app->bind(
AsceticSoft\Rowcast\ConnectionInterface::class,
function ($app) {
$inner = $app->make(AsceticSoft\Rowcast\Connection::class);
$profiler = new RowcastProfiler(
new DatabaseQueryProfileStore(), // Custom store
new CustomParameterSanitizer(), // Context-aware sanitization
slowQueryThresholdMs: (float) config('rowcast.profiler.threshold')
);
return new ConnectionProfiler($inner, $profiler);
}
);
config/rowcast.php.InMemoryQueryProfileStore with a database-backed store (e.g., using Laravel’s query builder) or Redis for scalability.class DatabaseQueryProfileStore implements QueryProfileStore {
public function addProfile(QueryProfile $profile) {
DB::table('query_profiles')->insert([
'sql' => $profile->sql,
'duration_ms' => $profile->durationMs,
'parameters' => json_encode($profile->parameters),
'created_at' => now(),
'context' => request()->header('X-Request-ID'), // Add context
]);
}
public function getProfiles(): array {
return DB::table('query_profiles')
->orderBy('created_at', 'desc')
->limit(100)
->get()
->map(fn ($record) => new QueryProfile(
$record->sql,
$record->duration_ms,
json_decode($record->parameters, true)
));
}
}
How can I help you explore Laravel packages today?