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.
Completed
Push — master ( 3e8a8b...c5325d )
by Andrei
01:27
created

buildRevisionDataFromPivotedRelation()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 44

Duplication

Lines 18
Ratio 40.91 %

Importance

Changes 0
Metric Value
dl 18
loc 44
c 0
b 0
f 0
rs 9.216
cc 4
nc 5
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->getOriginal();
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 getOriginal() 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()) {
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->getOriginal() 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
            $pivot = $model->pivot;
139
140 View Code Duplication
            foreach ($model->getOriginal() 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...
141
                $data = $this->dataWithForeignKeys(
142
                    $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...
143
                );
144
145
                $data = $this->dataWithAttributeValue(
146
                    $data, $model->getAttributes(), $index, $field, $value
147
                );
148
            }
149
150 View Code Duplication
            foreach ($pivot->getOriginal() 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...
151
                $data = $this->dataWithPivotForeignKeys(
152
                    $data, $pivot->getKeyName(), $pivot->getForeignKey(), $pivot->getRelatedKey()
153
                );
154
155
                $data = $this->dataWithPivotAttributeValue(
156
                    $data, $pivot->getAttributes(), $index, $field, $value
157
                );
158
            }
159
        }
160
161
        return $data;
162
    }
163
164
    /**
165
     * Verify if the data array contains the foreign keys.
166
     *
167
     * @param array $data
168
     * @return bool
169
     */
170
    protected function dataHasForeignKeys(array $data = []): bool
171
    {
172
        return $data['records']['primary_key'] && $data['records']['foreign_key'];
173
    }
174
175
    /**
176
     * Verify if the data array contains the pivoted foreign keys.
177
     *
178
     * @param array $data
179
     * @return bool
180
     */
181
    protected function dataHasPivotForeignKeys(array $data = []): bool
182
    {
183
        return $data['pivots']['primary_key'] && $data['pivots']['foreign_key'] && $data['pivots']['related_key'];
184
    }
185
186
    /**
187
     * Attach the foreign keys to the data array.
188
     *
189
     * @param array $data
190
     * @param string $primaryKey
191
     * @param string $foreignKey
192
     * @return array
193
     */
194
    protected function dataWithForeignKeys(array $data, string $primaryKey, string $foreignKey): array
195
    {
196
        if (! $this->dataHasForeignKeys($data)) {
197
            $data['records']['primary_key'] = $primaryKey;
198
            $data['records']['foreign_key'] = $foreignKey;
199
        }
200
201
        return $data;
202
    }
203
204
    /**
205
     * Attach the pivoted foreign keys to the data array.
206
     *
207
     * @param array $data
208
     * @param string $primaryKey
209
     * @param string $foreignKey
210
     * @param string $relatedKey
211
     * @return array
212
     */
213
    protected function dataWithPivotForeignKeys(array $data, string $primaryKey, string $foreignKey, string $relatedKey): array
214
    {
215
        if (! $this->dataHasPivotForeignKeys($data)) {
216
            $data['pivots']['primary_key'] = $primaryKey;
217
            $data['pivots']['foreign_key'] = $foreignKey;
218
            $data['pivots']['related_key'] = $relatedKey;
219
        }
220
221
        return $data;
222
    }
223
224
    /**
225
     * Build the data array with each attribute<->value set for the given model.
226
     *
227
     * @param array $data
228
     * @param array $attributes
229
     * @param int $index
230
     * @param string $field
231
     * @param string|int|null $value
232
     * @return array
233
     */
234 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...
235
    {
236
        if (array_key_exists($field, $attributes)) {
237
            $data['records']['items'][$index][$field] = $value;
238
        }
239
240
        return $data;
241
    }
242
243
    /**
244
     * Build the data array with each pivoted attribute<->value set for the given model.
245
     *
246
     * @param array $data
247
     * @param array $attributes
248
     * @param int $index
249
     * @param string $field
250
     * @param string|int|null $value
251
     * @return array
252
     */
253 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...
254
    {
255
        if (array_key_exists($field, $attributes)) {
256
            $data['pivots']['items'][$index][$field] = $value;
257
        }
258
259
        return $data;
260
    }
261
262
    /**
263
     * Get the relations that should be revisionable alongside the original model.
264
     *
265
     * @return array
266
     * @throws \ReflectionException
267
     */
268
    protected function getRelationsForRevision(): array
269
    {
270
        $relations = [];
271
272
        foreach (RelationHelper::getModelRelations($this) as $relation => $attributes) {
273
            if (in_array($relation, $this->revisionOptions->revisionRelations)) {
274
                $relations[$relation] = $attributes;
275
            }
276
        }
277
278
        return $relations;
279
    }
280
}
281