GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

buildRevisionDataFromDirectRelation()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
c 0
b 0
f 0
rs 9.504
cc 3
nc 3
nop 2
1
<?php
2
3
namespace Neurony\Revisions\Traits;
4
5
use Neurony\Revisions\Helpers\RelationHelper;
6
7
trait SaveRevisionJsonRepresentation
8
{
9
    /**
10
     * Build the entire data array for further json insert into the revisions table.
11
     *
12
     * Extract the actual model's data.
13
     * Extract all of the model's direct relations data.
14
     * Extract all of the model's pivoted relations data.
15
     *
16
     * @return array
17
     * @throws \ReflectionException
18
     */
19
    protected function buildRevisionData(): array
20
    {
21
        $data = $this->buildRevisionDataFromModel();
22
23
        foreach ($this->getRelationsForRevision() as $relation => $attributes) {
24
            if (RelationHelper::isDirect($attributes['type'])) {
25
                $data['relations'][$relation] = $this->buildRevisionDataFromDirectRelation($relation, $attributes);
26
            }
27
28
            if (RelationHelper::isPivoted($attributes['type'])) {
29
                $data['relations'][$relation] = $this->buildRevisionDataFromPivotedRelation($relation, $attributes);
30
            }
31
        }
32
33
        return $data;
34
    }
35
36
    /**
37
     * Get all the fields that should be revisioned from the model instance.
38
     * Automatically unset primary and timestamp keys.
39
     * Also count for revision fields if any are set on the model.
40
     *
41
     * @return array
42
     */
43
    protected function buildRevisionDataFromModel(): array
44
    {
45
        $data = $this->wasRecentlyCreated === true ? $this->getAttributes() : $this->getRawOriginal();
0 ignored issues
show
Bug introduced by
The property wasRecentlyCreated does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
It seems like getAttributes() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
Bug introduced by
It seems like getRawOriginal() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
46
47
        $fieldsToRevision = $this->revisionOptions->revisionFields;
0 ignored issues
show
Bug introduced by
The property revisionOptions does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
48
        $fieldsToNotRevision = $this->revisionOptions->revisionNotFields;
49
50
        unset($data[$this->getKeyName()]);
51
52
        if ($this->usesTimestamps() && ! $this->revisionOptions->revisionTimestamps) {
0 ignored issues
show
Bug introduced by
It seems like usesTimestamps() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
53
            unset($data[$this->getCreatedAtColumn()]);
54
            unset($data[$this->getUpdatedAtColumn()]);
55
        }
56
57
        if ($fieldsToRevision && is_array($fieldsToRevision) && ! empty($fieldsToRevision)) {
58
            foreach ($data as $field => $value) {
59
                if (! in_array($field, $fieldsToRevision)) {
60
                    unset($data[$field]);
61
                }
62
            }
63
        } elseif ($fieldsToNotRevision && is_array($fieldsToNotRevision) && ! empty($fieldsToNotRevision)) {
64
            foreach ($data as $field => $value) {
65
                if (in_array($field, $fieldsToNotRevision)) {
66
                    unset($data[$field]);
67
                }
68
            }
69
        }
70
71
        return $data;
72
    }
73
74
    /**
75
     * Extract revisionable data from a model's relation.
76
     * Extract the type, class and related records.
77
     * Store the extracted data into an array to be json inserted into the revisions table.
78
     *
79
     * @param string $relation
80
     * @param array $attributes
81
     * @return array
82
     */
83
    protected function buildRevisionDataFromDirectRelation(string $relation, array $attributes = []): array
84
    {
85
        $data = [
86
            'type' => $attributes['type'],
87
            'class' => get_class($attributes['model']),
88
            'records' => [
89
                'primary_key' => null,
90
                'foreign_key' => null,
91
                'items' => [],
92
            ],
93
        ];
94
95
        foreach ($this->{$relation}()->get() as $index => $model) {
96
            $data = $this->dataWithForeignKeys(
97
                $data, $model->getKeyName(), $this->getForeignKey()
0 ignored issues
show
Bug introduced by
It seems like getForeignKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
98
            );
99
100
            foreach ($model->getRawOriginal() as $field => $value) {
101
                $data = $this->dataWithAttributeValue(
102
                    $data, $model->getAttributes(), $index, $field, $value
103
                );
104
            }
105
        }
106
107
        return $data;
108
    }
109
110
    /**
111
     * Extract revisionable data from a model's relation pivot table.
112
     * Extract the type, class, related records and pivot values.
113
     * Store the extracted data into an array to be json inserted into the revisions table.
114
     *
115
     * @param string $relation
116
     * @param array $attributes
117
     * @return array
118
     */
119
    protected function buildRevisionDataFromPivotedRelation(string $relation, array $attributes = []): array
120
    {
121
        $data = [
122
            'type' => $attributes['type'],
123
            'class' => get_class($attributes['model']),
124
            'records' => [
125
                'primary_key' => null,
126
                'foreign_key' => null,
127
                'items' => [],
128
            ],
129
            'pivots' => [
130
                'primary_key' => null,
131
                'foreign_key' => null,
132
                'related_key' => null,
133
                'items' => [],
134
            ],
135
        ];
136
137
        foreach ($this->{$relation}()->get() as $index => $model) {
138
            $accessor = $this->{$relation}()->getPivotAccessor();
139
            $pivot = $model->{$accessor};
140
141 View Code Duplication
            foreach ($model->getRawOriginal() as $field => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
142
                $data = $this->dataWithForeignKeys(
143
                    $data, $model->getKeyName(), $this->getForeignKey()
0 ignored issues
show
Bug introduced by
It seems like getForeignKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
144
                );
145
146
                $data = $this->dataWithAttributeValue(
147
                    $data, $model->getAttributes(), $index, $field, $value
148
                );
149
            }
150
151 View Code Duplication
            foreach ($pivot->getRawOriginal() as $field => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
                $data = $this->dataWithPivotForeignKeys(
153
                    $data, $pivot->getKeyName(), $pivot->getForeignKey(), $pivot->getRelatedKey()
154
                );
155
156
                $data = $this->dataWithPivotAttributeValue(
157
                    $data, $pivot->getAttributes(), $index, $field, $value
158
                );
159
            }
160
        }
161
162
        return $data;
163
    }
164
165
    /**
166
     * Verify if the data array contains the foreign keys.
167
     *
168
     * @param array $data
169
     * @return bool
170
     */
171
    protected function dataHasForeignKeys(array $data = []): bool
172
    {
173
        return $data['records']['primary_key'] && $data['records']['foreign_key'];
174
    }
175
176
    /**
177
     * Verify if the data array contains the pivoted foreign keys.
178
     *
179
     * @param array $data
180
     * @return bool
181
     */
182
    protected function dataHasPivotForeignKeys(array $data = []): bool
183
    {
184
        return $data['pivots']['primary_key'] && $data['pivots']['foreign_key'] && $data['pivots']['related_key'];
185
    }
186
187
    /**
188
     * Attach the foreign keys to the data array.
189
     *
190
     * @param array $data
191
     * @param string $primaryKey
192
     * @param string $foreignKey
193
     * @return array
194
     */
195
    protected function dataWithForeignKeys(array $data, string $primaryKey, string $foreignKey): array
196
    {
197
        if (! $this->dataHasForeignKeys($data)) {
198
            $data['records']['primary_key'] = $primaryKey;
199
            $data['records']['foreign_key'] = $foreignKey;
200
        }
201
202
        return $data;
203
    }
204
205
    /**
206
     * Attach the pivoted foreign keys to the data array.
207
     *
208
     * @param array $data
209
     * @param string $primaryKey
210
     * @param string $foreignKey
211
     * @param string $relatedKey
212
     * @return array
213
     */
214
    protected function dataWithPivotForeignKeys(array $data, string $primaryKey, string $foreignKey, string $relatedKey): array
215
    {
216
        if (! $this->dataHasPivotForeignKeys($data)) {
217
            $data['pivots']['primary_key'] = $primaryKey;
218
            $data['pivots']['foreign_key'] = $foreignKey;
219
            $data['pivots']['related_key'] = $relatedKey;
220
        }
221
222
        return $data;
223
    }
224
225
    /**
226
     * Build the data array with each attribute<->value set for the given model.
227
     *
228
     * @param array $data
229
     * @param array $attributes
230
     * @param int $index
231
     * @param string $field
232
     * @param string|int|null $value
233
     * @return array
234
     */
235 View Code Duplication
    protected function dataWithAttributeValue(array $data, array $attributes, int $index, string $field, $value = null): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
236
    {
237
        if (array_key_exists($field, $attributes)) {
238
            $data['records']['items'][$index][$field] = $value;
239
        }
240
241
        return $data;
242
    }
243
244
    /**
245
     * Build the data array with each pivoted attribute<->value set for the given model.
246
     *
247
     * @param array $data
248
     * @param array $attributes
249
     * @param int $index
250
     * @param string $field
251
     * @param string|int|null $value
252
     * @return array
253
     */
254 View Code Duplication
    protected function dataWithPivotAttributeValue(array $data, array $attributes, int $index, string $field, $value = null): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
255
    {
256
        if (array_key_exists($field, $attributes)) {
257
            $data['pivots']['items'][$index][$field] = $value;
258
        }
259
260
        return $data;
261
    }
262
263
    /**
264
     * Get the relations that should be revisionable alongside the original model.
265
     *
266
     * @return array
267
     * @throws \ReflectionException
268
     */
269
    protected function getRelationsForRevision(): array
270
    {
271
        $relations = [];
272
273
        foreach (RelationHelper::getModelRelations($this) as $relation => $attributes) {
274
            if (in_array($relation, $this->revisionOptions->revisionRelations)) {
275
                $relations[$relation] = $attributes;
276
            }
277
        }
278
279
        return $relations;
280
    }
281
}
282