Data Export

AuditChain provides two methods to export personal data from your models: exportPersonalData() for a simple data extract, and exportFullSubjectData() for a complete subject access response including the full audit trail. These methods make it straightforward to fulfill data subject requests, such as those required by GDPR Article 15 (right of access).

Simple Export

exportPersonalData() returns the current values of all fields annotated as personal data:

$data = $user->exportPersonalData();
// [
//     'email' => 'john@example.com',
//     'name' => 'John Doe',
//     'phone' => '+1-555-0123',
// ]

This is useful when you need a quick snapshot of the personal data held for a data subject.

Full Subject Access

exportFullSubjectData() returns both the personal data and the complete audit trail for the model. This provides everything needed to respond to a comprehensive Article 15 subject access request:

$export = $user->exportFullSubjectData();
// [
//     'personal_data' => [
//         'email' => 'john@example.com',
//         'name' => 'John Doe',
//     ],
//     'audit_trail' => [
//         [
//             'id' => '01hy3x...',
//             'event' => 'created',
//             'old_values' => null,
//             'new_values' => ['email' => 'john@example.com', 'name' => 'John Doe'],
//             'personal_data_accessed' => ['email', 'name'],
//             'ip_address' => '192.168.1.1',
//             'user_agent' => 'Mozilla/5.0...',
//             'batch_uuid' => null,
//             'context' => null,
//             'created_at' => '2026-01-15T10:30:00+00:00',
//         ],
//         [
//             'id' => '01hy4a...',
//             'event' => 'updated',
//             'old_values' => ['email' => 'john@example.com'],
//             'new_values' => ['email' => 'john.doe@example.com'],
//             'personal_data_accessed' => ['email'],
//             'ip_address' => '192.168.1.1',
//             'user_agent' => 'Mozilla/5.0...',
//             'batch_uuid' => null,
//             'context' => null,
//             'created_at' => '2026-02-01T14:22:00+00:00',
//         ],
//     ],
// ]

What Is Included

The audit trail entries contain all the information a data subject might need to understand how their data has been processed:

  • event — what happened (created, updated, deleted, etc.)
  • old_values / new_values — what changed
  • personal_data_accessed — which personal data fields were involved
  • ip_address / user_agent — where the action originated
  • batch_uuid / context — operational metadata about the action
  • created_at — when it happened (ISO 8601 format)

What Is Excluded

The hash and prev_hash fields are intentionally excluded from the export. These are internal cryptographic chain fields used for tamper detection and are not relevant to a data subject's access request.

Building a Response Endpoint

Here is a practical example of an API endpoint that responds to subject access requests:

use Illuminate\Http\JsonResponse;

class SubjectAccessController extends Controller
{
    public function show(User $user): JsonResponse
    {
        $this->authorize('viewPersonalData', $user);

        return response()->json([
            'subject' => $user->exportFullSubjectData(),
            'exported_at' => now()->toIso8601String(),
        ]);
    }
}

Tip: GDPR Article 12(3) requires you to respond to subject access requests within one month. Consider building an admin interface or automated workflow so these requests can be fulfilled promptly.

Exporting Across Multiple Models

If a data subject's personal data is spread across multiple models, aggregate the exports:

$user = User::find($id);

$export = [
    'user' => $user->exportFullSubjectData(),
    'orders' => $user->orders->map->exportFullSubjectData()->all(),
    'subscriptions' => $user->subscriptions->map->exportFullSubjectData()->all(),
];

Each model must implement the Auditable interface and use HasActivityLog or HasAuditTrail for this to work.