Completed
Push — master ( 627e16...05425c )
by Freek
07:04
created

DetectsChanges::logChanges()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 1
nop 1
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Spatie\Activitylog\Traits;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Spatie\Activitylog\Exceptions\CouldNotLogChanges;
7
8
trait DetectsChanges
9
{
10
    protected $oldAttributes = [];
11
12
    protected static function bootDetectsChanges()
13
    {
14
        if (static::eventsToBeRecorded()->contains('updated')) {
15
            static::updating(function (Model $model) {
16
17
                //temporary hold the original attributes on the model
18
                //as we'll need these in the updating event
19
                $oldValues = $model->replicate()->setRawAttributes($model->getOriginal());
20
21
                $model->oldAttributes = static::logChanges($oldValues);
22
            });
23
        }
24
    }
25
26
    public function attributesToBeLogged(): array
27
    {
28
        if (! isset(static::$logAttributes)) {
29
            return [];
30
        }
31
32
        return static::$logAttributes;
33
    }
34
35
    public function attributeValuesToBeLogged(string $processingEvent): array
36
    {
37
        if (! count($this->attributesToBeLogged())) {
38
            return [];
39
        }
40
41
        $properties['attributes'] = static::logChanges($this);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$properties was never initialized. Although not strictly required by PHP, it is generally a good practice to add $properties = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
42
43
        if (static::eventsToBeRecorded()->contains('updated') && $processingEvent == 'updated') {
44
            $nullProperties = array_fill_keys(array_keys($properties['attributes']), null);
45
46
            $properties['old'] = array_merge($nullProperties, $this->oldAttributes);
47
        }
48
49
        return $properties;
50
    }
51
52
    public static function logChanges(Model $model): array
53
    {
54
        return collect($model->attributesToBeLogged())->mapWithKeys(
55
            function ($attribute) use ($model) {
56
                if (str_contains($attribute, '.')) {
57
                    return self::getRelatedModelAttributeValue($model, $attribute);
58
                }
59
60
                return collect($model)->only($attribute);
61
            }
62
        )->toArray();
63
    }
64
65
66
    protected static function getRelatedModelAttributeValue($model, $attribute): array {
67
        if (substr_count($attribute, '.') > 1) {
68
            throw CouldNotLogChanges::invalidAttribute($attribute);
69
        }
70
71
        list($relatedModelName, $relatedAttribute) = explode('.', $attribute);
72
73
        $relatedModel = $model->$relatedModelName ?? $model->$relatedModelName();
74
75
        return ["{$relatedModelName}.{$relatedAttribute}" => $relatedModel->$relatedAttribute];
76
    }
77
}
78