Completed
Pull Request — master (#651)
by Voyula
02:15
created

ActivityLogger   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 201
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 95.35%

Importance

Changes 0
Metric Value
dl 0
loc 201
ccs 82
cts 86
cp 0.9535
rs 10
c 0
b 0
f 0
wmc 28
lcom 1
cbo 10

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A setLogStatus() 0 6 1
A performedOn() 0 6 1
A on() 0 4 1
A causedBy() 0 12 2
A by() 0 4 1
A causedByAnonymous() 0 7 1
A byAnonymous() 0 4 1
A withProperties() 0 6 1
A tap() 0 6 1
A enableLogging() 0 6 1
A withProperty() 0 6 1
A useLog() 0 6 1
A inLog() 0 4 1
A disableLogging() 0 6 1
A log() 0 19 2
A normalizeCauser() 0 16 5
A getActivity() 0 12 2
A replacePlaceholders() 0 24 3
1
<?php
2
3
namespace Spatie\Activitylog;
4
5
use Spatie\String\Str;
6
use Illuminate\Support\Arr;
7
use Illuminate\Auth\AuthManager;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Support\Traits\Macroable;
10
use Illuminate\Contracts\Config\Repository;
11
use Spatie\Activitylog\Exceptions\CouldNotLogActivity;
12
use Spatie\Activitylog\Contracts\Activity as ActivityContract;
13
14
class ActivityLogger
15
{
16
    use Macroable;
17
18
    /** @var \Illuminate\Auth\AuthManager */
19
    protected $auth;
20
21
    protected $defaultLogName = '';
22
23
    /** @var string */
24
    protected $authDriver;
25
26
    /** @var \Spatie\Activitylog\ActivityLogStatus */
27
    protected $logStatus;
28
29
    /** @var \Spatie\Activitylog\Contracts\Activity */
30
    protected $activity;
31
32 132
    public function __construct(AuthManager $auth, Repository $config, ActivityLogStatus $logStatus)
33
    {
34 132
        $this->auth = $auth;
35
36 132
        $this->authDriver = $config['activitylog']['default_auth_driver'] ?? $auth->getDefaultDriver();
37
38 132
        $this->defaultLogName = $config['activitylog']['default_log_name'];
39
40 132
        $this->logStatus = $logStatus;
41 132
    }
42
43 132
    public function setLogStatus(ActivityLogStatus $logStatus)
44
    {
45 132
        $this->logStatus = $logStatus;
46
47 132
        return $this;
48
    }
49
50 24
    public function performedOn(Model $model)
51
    {
52 24
        $this->getActivity()->subject()->associate($model);
53
54 24
        return $this;
55
    }
56
57 16
    public function on(Model $model)
58
    {
59 16
        return $this->performedOn($model);
60
    }
61
62 132
    public function causedBy($modelOrId)
63
    {
64 132
        if ($modelOrId === null) {
65 128
            return $this;
66
        }
67
68 40
        $model = $this->normalizeCauser($modelOrId);
69
70 40
        $this->getActivity()->causer()->associate($model);
71
72 40
        return $this;
73
    }
74
75 20
    public function by($modelOrId)
76
    {
77 20
        return $this->causedBy($modelOrId);
78
    }
79
80 8
    public function causedByAnonymous()
81
    {
82 8
        $this->activity->causer_id = null;
0 ignored issues
show
Bug introduced by
Accessing causer_id on the interface Spatie\Activitylog\Contracts\Activity suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
83 8
        $this->activity->causer_type = null;
0 ignored issues
show
Bug introduced by
Accessing causer_type on the interface Spatie\Activitylog\Contracts\Activity suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
84
85 8
        return $this;
86
    }
87
88 4
    public function byAnonymous()
89
    {
90 4
        return $this->causedByAnonymous();
91
    }
92
93 132
    public function withProperties($properties)
94
    {
95 132
        $this->getActivity()->properties = collect($properties);
0 ignored issues
show
Bug introduced by
Accessing properties on the interface Spatie\Activitylog\Contracts\Activity suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
96
97 132
        return $this;
98
    }
99
100 4
    public function withProperty(string $key, $value)
101
    {
102 4
        $this->getActivity()->properties = $this->getActivity()->properties->put($key, $value);
0 ignored issues
show
Bug introduced by
Accessing properties on the interface Spatie\Activitylog\Contracts\Activity suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
103
104 4
        return $this;
105
    }
106
107 132
    public function useLog(string $logName)
108
    {
109 132
        $this->getActivity()->log_name = $logName;
0 ignored issues
show
Bug introduced by
Accessing log_name on the interface Spatie\Activitylog\Contracts\Activity suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
110
111 132
        return $this;
112
    }
113
114
    public function inLog(string $logName)
115
    {
116
        return $this->useLog($logName);
117
    }
118
119 4
    public function tap(callable $callback, string $eventName = null)
120
    {
121 4
        call_user_func($callback, $this->getActivity(), $eventName);
122
123 4
        return $this;
124
    }
125
126 4
    public function enableLogging()
127
    {
128 4
        $this->logStatus->enable();
129
130 4
        return $this;
131
    }
132
133 4
    public function disableLogging()
134
    {
135 4
        $this->logStatus->disable();
136
137 4
        return $this;
138
    }
139
140 132
    public function log(string $description)
141
    {
142 132
        if ($this->logStatus->disabled()) {
143 8
            return;
144
        }
145
146 124
        $activity = $this->activity;
147
148 124
        $activity->description = $this->replacePlaceholders(
0 ignored issues
show
Bug introduced by
Accessing description on the interface Spatie\Activitylog\Contracts\Activity suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
149 124
            $activity->description ?? $description,
0 ignored issues
show
Bug introduced by
Accessing description on the interface Spatie\Activitylog\Contracts\Activity suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
150 62
            $activity
151
        );
152
153 124
        $activity->save();
154
155 124
        $this->activity = null;
156
157 124
        return $activity;
158
    }
159
160 40
    protected function normalizeCauser($modelOrId): Model
161
    {
162 40
        if ($modelOrId instanceof Model) {
163 36
            return $modelOrId;
164
        }
165
166 4
        $guard = $this->auth->guard($this->authDriver);
167 4
        $provider = method_exists($guard, 'getProvider') ? $guard->getProvider() : null;
168 4
        $model = method_exists($provider, 'retrieveById') ? $provider->retrieveById($modelOrId) : null;
169
170 4
        if ($model instanceof Model) {
171 4
            return $model;
172
        }
173
174
        throw CouldNotLogActivity::couldNotDetermineUser($modelOrId);
175
    }
176
177 124
    protected function replacePlaceholders(string $description, ActivityContract $activity): string
178
    {
179
        return preg_replace_callback('/:[a-z0-9._-]+/i', function ($match) use ($activity) {
180 8
            $match = $match[0];
181
182 8
            $attribute = (string) (new Str($match))->between(':', '.');
183
184 8
            if (! in_array($attribute, ['subject', 'causer', 'properties'])) {
185 4
                return $match;
186
            }
187
188 4
            $propertyName = substr($match, strpos($match, '.') + 1);
189
190 4
            $attributeValue = $activity->$attribute;
191
192 4
            if (is_null($attributeValue)) {
193
                return $match;
194
            }
195
196 4
            $attributeValue = $attributeValue->toArray();
197
198 4
            return Arr::get($attributeValue, $propertyName, $match);
199 124
        }, $description);
200
    }
201
202 132
    protected function getActivity(): ActivityContract
203
    {
204 132
        if (! $this->activity instanceof ActivityContract) {
205 132
            $this->activity = ActivitylogServiceProvider::getActivityModelInstance();
206
            $this
207 132
                ->useLog($this->defaultLogName)
208 132
                ->withProperties([])
209 132
                ->causedBy($this->auth->guard($this->authDriver)->user());
210
        }
211
212 132
        return $this->activity;
213
    }
214
}
215