Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
Auditable
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
7 / 7
9
100.00% covered (success)
100.00%
1 / 1
 getActivitylogOptions
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 tapActivity
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 auditOnly
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 auditExcept
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 auditName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 auditLabel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 auditSubjectLabel
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace App\Support;
4
5use Illuminate\Support\Str;
6use Spatie\Activitylog\Contracts\Activity;
7use Spatie\Activitylog\LogOptions;
8use Spatie\Activitylog\Traits\LogsActivity;
9
10/**
11 * Project-wide activity logging with sensible defaults, so a model only has to
12 * `use Auditable` (no boilerplate). What's recorded shows up on the
13 * Activity log page (People → Activity log), gated by the `audit_log` feature.
14 *
15 * Per-model overrides — override any of these methods:
16 *   protected function auditOnly(): array   { return ['name', 'price']; }  // whitelist
17 *   protected function auditExcept(): array { return ['slug']; }           // extra excludes
18 *   protected function auditName(): string  { return 'product'; }          // log group
19 *   protected function auditLabel(): string { return $this->ref; }         // human label
20 */
21trait Auditable
22{
23    use LogsActivity;
24
25    public function getActivitylogOptions(): LogOptions
26    {
27        return LogOptions::defaults()
28            ->logOnly($this->auditOnly())
29            ->logExcept(array_merge(
30                ['id', 'created_at', 'updated_at', 'deleted_at', 'password', 'remember_token', 'created_by'],
31                $this->auditExcept(),
32            ))
33            ->logOnlyDirty()
34            ->dontSubmitEmptyLogs()
35            ->useLogName($this->auditName());
36    }
37
38    public function tapActivity(Activity $activity, string $eventName): void
39    {
40        // Only rewrite the description for automatic model events (create /
41        // update / delete). A manual activity('…')->log('…') passes an empty
42        // event name and already carries its own sentence — leave it alone.
43        if ($eventName !== '') {
44            $activity->description = ucfirst($eventName) . ' ' . $this->auditSubjectLabel();
45        }
46    }
47
48    protected function auditOnly(): array
49    {
50        return ['*'];
51    }
52
53    protected function auditExcept(): array
54    {
55        return [];
56    }
57
58    protected function auditName(): string
59    {
60        return Str::snake(class_basename(static::class));
61    }
62
63    protected function auditLabel(): ?string
64    {
65        return $this->name ?? $this->title ?? $this->ref ?? $this->invoice_no ?? null;
66    }
67
68    protected function auditSubjectLabel(): string
69    {
70        $type = Str::headline(class_basename(static::class));
71        $label = $this->auditLabel();
72
73        return $label ? "{$type} “{$label}" : "{$type} #{$this->getKey()}";
74    }
75}