Audit Logging
This package supports audit logging in three common ways:
- Dynamic Record API (automatic) with an optional per-table
customAuditLoghook. - Controller-driven auditing with a custom
getAuditQuery()snapshot. - Model-driven auditing using
AuditableTrait.
Controller Auditing (Manual)
Use this approach when you want full control over what gets written to the audit log, or when you are not using AuditableTrait.
Example: insertAuditLog() + getAuditQuery()
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Mylekha\RecordApi\Enums\AuditLogEventEnum;
use Mylekha\RecordApi\Services\AuditLogService;
class CompanyController extends Controller
{
public function update(Request $request, int $id)
{
DB::table('companies')->where('id', $id)->update([
'name' => $request->input('name'),
]);
AuditLogService::insertAuditLog(
auditLogEventEnum: AuditLogEventEnum::UPDATED,
entityClass: \App\Models\Company::class,
queryData: $this->getAuditQuery($id),
);
return response()->json(['success' => true]);
}
public function getAuditQuery(int $id): array
{
$record = DB::table('companies')->where('id', $id)->first();
if (!$record) {
return [];
}
return AuditLogService::handleMapperQueryData((array) $record);
}
}Dynamic Record API Hook (Per Table)
When you use the package dynamic CRUD, audit logging can be customized per table via RecordTableType::customAuditLog.
RecordTableType Audit Options
RecordTableType provides two audit-related knobs for the Dynamic Record API:
disableAuditLog(bool): Skips built-in audit logging for create/update/delete for this table.customAuditLog(callable|string|array): Overrides built-in logging for this table. When it is configured and resolvable, the package calls your handler and does not callAuditLogService::insertAuditLog().
Example:
use Mylekha\RecordApi\Types\RecordTablePublic;
use Mylekha\RecordApi\Types\RecordTableType;
return [
'tables' => [
'companies' => new RecordTableType(
table: 'companies',
pmsName: 'company',
public: new RecordTablePublic(read: true, write: true),
disableAuditLog: false,
customAuditLog: [\App\Audit\CompanyAuditLogger::class, 'handle'],
),
],
];Handler signature:
use Mylekha\RecordApi\Enums\AuditLogEventEnum;
function handle(
AuditLogEventEnum $event,
string $entityClass,
array $auditData,
mixed $tenantId,
array $context
): voidNotes:
$auditDatashould include anid(orentity_id) for update/delete events; otherwise the audit entry is skipped.$contextcontains:request,table,operation(create|update|delete), andrecord_context.
Global Audit Config That Affects RecordTableType
Audit logging also depends on the global audit config (config/audit.php):
audit.enabled: Must betrueor the package will not create audit logs.audit.queue_enabled: Whentrue, audit writes are dispatched to a job (instead of being written inline).audit.log_relationships: Whentrue, audit snapshots include configured relationships (default:false).
If you enable tenant mode (record.enable_tenant_id = true), audit logs also store the tenant column (default: tenant_id).
Audit Formatting & Labels
Audit title, subject, and recap values are generated from config and normalized by AuditLogService::generateLabel() (camelCase, snake_case, and hyphenated values are converted into readable labels).
Subject Fields
audit.subject_fields defines the ordered list of fields to use for the audit subject. If the list is empty, the subject is blank.
Example:
'subject_fields' => ['ref_number', 'name'],Entity Labels
audit.entity_labels defines explicit labels per entity. If a label is not defined, the value is derived from generateLabel() instead of a hardcoded default.
Example:
'entity_labels' => [
'invoices' => 'Invoice',
'sale_orders' => 'Sale Receipt',
],Recap Generation
For updated records, the recap is generated from changed main fields:
audit.recap_entities: Entities that use the detailed recap formatter.audit.main_field_labels: Field label map used by detailed recaps and generic recaps.audit.recap_max_fields: Max number of fields shown in generic recaps. Additional fields are summarized as “and N more”.- Technical fields like
id,created_at,updated_at, anddeleted_atare excluded from recap changes.
Manual Cache Clear
If your controller, queue, or command updates data outside the Dynamic Record API, you can clear table cache manually:
use Mylekha\RecordApi\Services\RecordCacheService;
$service = app(RecordCacheService::class);
$service->clearTableCache('settings', $tenantId);
$service->clearCacheForTables(['settings', 'users'], $tenantId);Model Auditing (Eloquent)
Apply AuditableTrait to an Eloquent model to automatically log create/update/delete events.
use Illuminate\Database\Eloquent\Model;
use Mylekha\RecordApi\Traits\AuditableTrait;
class Company extends Model
{
use AuditableTrait;
protected $guarded = [];
}