Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ActivityLog
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 3
42
0.00% covered (danger)
0.00%
0 / 1
 addActivity
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
6
 getChangedColumns
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 user
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Models;
4
5use App\Enums\ActivityLogs\ActivityLogsEventEnum;
6use Carbon\Carbon;
7use Illuminate\Database\Eloquent\Factories\HasFactory;
8use Illuminate\Database\Eloquent\Model;
9use Illuminate\Notifications\Notifiable;
10use Illuminate\Support\Facades\Schema;
11
12/**
13 * @property string                          $model      Target model.
14 * @property string                          $model_id   Id of the target model.
15 * @property string                          $event      Event of this activity (ActivityLogsEventEnum).
16 * @property string                          $data       Changes.
17 * @property-read \Illuminate\Support\Carbon $created_at Created date.
18 *
19 * @method public static function addActivity($model, $eventEnum) Add new activity to the activity logs list.
20 * @method public static function getValuesChanged($activity, $model, $eventEnum)
21 * Get old, new and type of values changed.
22 *
23 * @property-read \App\Models\User $user User BelongsTo relation.
24 */
25class ActivityLog extends Model
26{
27    use HasFactory;
28    use Notifiable;
29
30    /**
31     * Indicates if the model should be timestamped.
32     *
33     * @var boolean
34     */
35    public $timestamps = false;
36
37    /**
38     * The attributes that are mass assignable.
39     *
40     * @var array<int, string>
41     */
42    protected $fillable = [
43        'is_anonymous',
44        'model_class',
45        'model_id',
46        'event',
47        'data',
48        'created_at',
49    ];
50
51    /**
52     * The attributes that should be cast.
53     *
54     * @var array<string, string>
55     */
56    protected $casts = [
57        'is_anonymous' => 'bool',
58        'event'        => ActivityLogsEventEnum::class,
59        'data'         => 'json',
60        'created_at'   => 'datetime',
61    ];
62
63    // * METHODS
64
65    /**
66     * Add new activity to the activity logs list.
67     *
68     * @param \Illuminate\Database\Eloquent\Model           $model
69     * @param \App\Enums\ActivityLogs\ActivityLogsEventEnum $eventEnum
70     * @return void
71     */
72    public static function addActivity(Model $model, ActivityLogsEventEnum $eventEnum): void
73    {
74        $isAnonymous = true;
75        /** @var \Illuminate\Database\Eloquent\Model|null */
76        $userModel = auth('backend')->user();
77        if (is_object($userModel)) {
78            $userModel   = $userModel->getKeyForSelectQuery();
79            $isAnonymous = false;
80        }
81        $activity               = new self();
82        $activity->user_id      = $userModel;
83        $activity->is_console   = app()->runningInConsole();
84        $activity->is_anonymous = $isAnonymous;
85        $activity->model_class  = \get_class($model);
86        $activity->model_id     = $model->getKey();
87        $activity->event        = $eventEnum;
88        $activity->data         = static::getChangedColumns($activity, $model, $eventEnum);
89        $activity->created_at   = Carbon::now();
90        $activity->saveOrFail();
91    }
92
93    /**
94     * Get old, new columns that has changed.
95     *
96     * @param \self                                         $activity
97     * @param \Illuminate\Database\Eloquent\Model           $model
98     * @param \App\Enums\ActivityLogs\ActivityLogsEventEnum $eventEnum
99     * @return array|null
100     */
101    public static function getChangedColumns(self $activity, Model $model, ActivityLogsEventEnum $eventEnum): array|null
102    {
103        $modelClassName = $activity->model_class;
104        /** Get type of each fields of the target model */
105        $targetModel = $activity->model_class::where(
106            (new $modelClassName())->getRouteKeyName(),
107            $activity->model_id
108        )->first();
109        if ($targetModel != null) {
110            // phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
111            $targetModelTypes = collect($targetModel->toArray())
112                ->map(function ($field, $fieldIndex) use ($targetModel) {
113                    return Schema::getColumnType($targetModel->getTable(), $fieldIndex);
114                })->toArray();
115            // phpcs:enable
116        }
117        /** Return old, new and type of values changed */
118        return ($eventEnum === ActivityLogsEventEnum::updated) ?
119            array_intersect_key($targetModelTypes, $model->getChanges()) : null;
120    }
121
122    // * RELATIONS
123
124    /**
125     * User BelongsTo relation.
126     *
127     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
128     */
129    public function user()
130    {
131        return $this->belongsTo(User::class);
132    }
133}