Skip to content

Instantly share code, notes, and snippets.

@rodrigopedra
Last active June 20, 2024 21:32
Show Gist options
  • Save rodrigopedra/a4a91948bd41617a9b1a to your computer and use it in GitHub Desktop.
Save rodrigopedra/a4a91948bd41617a9b1a to your computer and use it in GitHub Desktop.
Laravel 5 Middleware for Database Transactions
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Response;
class DBTransaction
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
* @throws \Exception
*/
public function handle($request, Closure $next)
{
\DB::beginTransaction();
try {
$response = $next($request);
} catch (\Exception $e) {
\DB::rollBack();
throw $e;
}
if ($response instanceof Response && $response->getStatusCode() > 399) {
\DB::rollBack();
} else {
\DB::commit();
}
return $response;
}
}
@rodrigopedra
Copy link
Author

rodrigopedra commented Sep 22, 2022

@jomisacu

I like the implementation of the linked package, but I don´t see the difference in behavior you describe.

In this gist's implementation the transaction is rolled back earlier right when an exception happens. It won't prevent this exception to be handled by the exception handler which could potentially log the exception and build a new exception in response.

If i have a permissions system i could send a 403 (Forbidden) status code to a user that attempts to go to restricted area, and more, at this moment I could wish log these attempts to the database and take further actions later.

None of the implementation would automatically allow reporting the executed queries if no database exceptions were thrown when you "unauthorize" a user.

And just by having the UnauthorizedException attached to the response wouldn't log the successful queries either.

For logging database queries you can use DB@listen to listen for the QueryExecuted event.

@jomisacu
Copy link

@rodrigopedra thank you for the response.

Excuse me, i tried to say, log the attempts to the restricted area, not log executed queries. But, this is an arbitrary example and i refer to that i could send 403 status code without associate exception, only setting the status code in the response object.

Here the question is: must a response status code revert the transaction?

@rodrigopedra
Copy link
Author

Here the question is: must a response status code revert the transaction?

Well I believe so, as any status code from 400 on are considered either an user error (400-499) or a server error (500-599).

I would not expect an unauthorized request to perform a database operation. And nothing is preventing, on either middleware, an exception to be reported.

If you want your exceptions to be saved to a database, you should use a different database connection for the logger, this would allow logging anything regardless of any open transactions, and is actually a better approach as from an application perspective that a connection responsible for transactional data (application logic) to be different than your infrastructure connection(s) (logging, session, cache, etc...)

Imagine rolling back a session data change because it happened inside a transaction you manually opened and rolled back, regardless of using a middleware for automatic transaction handling.

When using different logging, session, cache and other drivers, rolling back or committing a transaction already does not affect any approaches.

If you believe this middleware should not consider just the status code as a criteria, you can change its code above. Or use the package you linked.

Both of them just offers different takes based on different opinions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment