API programmatique
Au-delà des commandes Artisan, AuditChain fournit une API programmatique pour la vérification de chaîne, le regroupement par batch, les métadonnées de contexte et le contrôle de la journalisation. Cela vous permet de construire des intégrations personnalisées, des tableaux de bord d'administration, des vérifications de santé et des workflows automatisés.
Vérification de chaîne
Utilisez AuditChainService pour vérifier la chaîne de hash depuis le code applicatif :
use GrayMatter\AuditChain\Services\AuditChainService; $service = app(AuditChainService::class); $result = $service->verifyChain();
La valeur de retour est un tableau avec trois clés :
[
'valid' => true, // bool -- si la chaîne est intacte
'checked' => 150, // int -- nombre de journaux chaînés vérifiés
'errors' => [], // array -- liste des détails d'erreur
]
Filtrage par model
Passez un type de model et un identifiant optionnel pour vérifier un sous-ensemble de la chaîne :
// Vérifier tous les journaux d'audit pour un type de model spécifique $result = $service->verifyChain(type: 'App\Models\Order'); // Vérifier les journaux pour une instance de model spécifique $result = $service->verifyChain(type: 'App\Models\Order', id: '42');
Lorsque des filtres sont appliqués, seule l'intégrité du hash est vérifiée (le hash stocké de chaque journal correspond à son hash recalculé). La continuité de la chaîne (liaison par prev_hash) est ignorée car la chaîne globale couvre tous les types de models — le filtrage retire des entrées du milieu de la chaîne.
Endpoint de vérification de santé
Construisez une route de vérification de santé qui expose l'état de la chaîne :
// routes/api.php use GrayMatter\AuditChain\Services\AuditChainService; Route::get('/health/audit-chain', function (AuditChainService $service) { $result = $service->verifyChain(); return response()->json([ 'status' => $result['valid'] ? 'ok' : 'compromised', 'checked' => $result['checked'], 'errors' => count($result['errors']), ], $result['valid'] ? 200 : 500); })->middleware('auth:sanctum');
Important : Protégez cet endpoint avec une authentification. L'état de la vérification de chaîne ne doit pas être accessible publiquement.
La facade AuditChain
La facade AuditChain fournit un contrôle à l'exécution sur la journalisation d'audit via le singleton AuditChainManager.
use GrayMatter\AuditChain\Facades\AuditChain;
batch()
Regroupez les entrées de journal d'audit associées sous un seul UUID :
AuditChain::batch(function () { $order->audit('shipped'); $order->update(['status' => 'shipped']); $inventory->update(['quantity' => $inventory->quantity - 1]); }); // Les 3 journaux d'audit partagent le même batch_uuid
Vous pouvez fournir votre propre identifiant de batch :
AuditChain::batch(function () { // ... }, batchId: 'import-2024-01-15');
Les batchs s'imbriquent en toute sécurité. Un batch interne utilise son propre UUID ; le batch externe reprend lorsque le batch interne est terminé :
AuditChain::batch(function () { $order->update(['status' => 'processing']); AuditChain::batch(function () { $payment->audit('captured'); $payment->update(['captured_at' => now()]); }); $order->update(['status' => 'shipped']); });
context()
Attachez des métadonnées libres à tous les journaux d'audit suivants :
AuditChain::context(['source' => 'csv_import', 'file' => 'users.csv']); User::create([...]); // le contexte est attaché à ce journal d'audit User::create([...]); // et à celui-ci aussi
Le contexte est additif — appeler context() plusieurs fois fusionne les valeurs :
AuditChain::context(['source' => 'api']); AuditChain::context(['request_id' => 'abc-123']); // Le contexte est maintenant : ['source' => 'api', 'request_id' => 'abc-123']
Note : Le contexte n'est pas inclus dans le calcul de la chaîne de hash. C'est une métadonnée opérationnelle — modifier le contexte n'invalide pas la chaîne.
clearContext()
Réinitialisez le contexte à un tableau vide :
AuditChain::clearContext();
Utilisez ceci après une importation ou une opération batch pour arrêter d'attacher le contexte aux journaux suivants.
withoutAudit()
Supprimez toute journalisation d'audit dans un callback :
AuditChain::withoutAudit(function () { User::factory()->count(1000)->create(); // Aucun journal d'audit créé });
Cas d'utilisation courants :
- Seeding de base de données — Evitez d'inonder la table d'audit avec des données de seed
- Migrations de données — Mises à jour en masse qui ne doivent pas être tracées
- Importations — Importations CSV ou API où vous journalisez l'importation elle-même mais pas chaque enregistrement individuel
withoutAudit() s'imbrique en toute sécurité. Si un appel externe désactive la journalisation, un appel interne ne la réactive pas.
Construire des intégrations personnalisées
Middleware pour le contexte de requête
Attachez automatiquement les métadonnées de requête à tous les journaux d'audit d'une requête :
// app/Http/Middleware/AuditContext.php namespace App\Http\Middleware; use Closure; use GrayMatter\AuditChain\Facades\AuditChain; use Illuminate\Http\Request; class AuditContext { public function handle(Request $request, Closure $next) { AuditChain::context([ 'request_id' => $request->header('X-Request-ID', (string) str()->uuid()), 'route' => $request->route()?->getName(), ]); return $next($request); } public function terminate(Request $request, $response): void { AuditChain::clearContext(); } }
Widget de tableau de bord d'administration
Interrogez les résultats de vérification pour un tableau de bord :
use GrayMatter\AuditChain\Services\AuditChainService; use GrayMatter\AuditChain\Models\AuditLog; $service = app(AuditChainService::class); $result = $service->verifyChain(); $stats = [ 'chain_valid' => $result['valid'], 'chain_checked' => $result['checked'], 'total_logs' => AuditLog::count(), 'today_logs' => AuditLog::where('created_at', '>=', now()->startOfDay())->count(), ];
Audit conditionnel
Combinez withoutAudit() avec la logique métier :
use GrayMatter\AuditChain\Facades\AuditChain; public function importUsers(array $records): void { AuditChain::context(['source' => 'user_import', 'count' => count($records)]); AuditChain::batch(function () use ($records) { // Journaliser l'événement d'importation sur un model de suivi $this->importLog->audit('started'); // Supprimer l'audit des enregistrements individuels AuditChain::withoutAudit(function () use ($records) { foreach ($records as $record) { User::create($record); } }); $this->importLog->audit('completed'); }); AuditChain::clearContext(); }
Cela enregistre le début et la fin de l'importation dans le journal d'audit (avec batch et contexte), mais ignore l'audit de chaque création individuelle d'utilisateur.