Passed
Push — master ( d79a37...05d8cd )
by Dan Michael O.
01:59
created

User::getAllIdentifierValues()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
c 0
b 0
f 0
nc 4
nop 0
dl 0
loc 10
rs 10
1
<?php
2
3
namespace App;
4
5
use Illuminate\Database\Eloquent\Builder;
0 ignored issues
show
Bug introduced by
The type Illuminate\Database\Eloquent\Builder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Illuminate\Foundation\Auth\User as Authenticatable;
0 ignored issues
show
Bug introduced by
The type Illuminate\Foundation\Auth\User was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use Illuminate\Notifications\Notifiable;
0 ignored issues
show
Bug introduced by
The type Illuminate\Notifications\Notifiable was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use Illuminate\Support\MessageBag;
0 ignored issues
show
Bug introduced by
The type Illuminate\Support\MessageBag was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
10
class User extends Authenticatable
11
{
12
13
    use Notifiable;
14
15
    /**
16
     * The attributes that are mass assignable.
17
     *
18
     * @var array
19
     */
20
    protected $fillable = ['in_alma', 'firstname', 'lastname', 'phone', 'email', 'lang'];
21
22
    /**
23
     * The attributes that should be cast to native types.
24
     *
25
     * @var array
26
     */
27
    protected $casts = [
28
        'blocks' => 'array',
29
        'fees' => 'integer',
30
    ];
31
32
   /**
33
     * The attributes that should be mutated to dates.
34
     *
35
     * @var array
36
     */
37
    protected $dates = ['last_loan_at'];
38
39
    /**
40
     * The accessors to append to the model's array form.
41
     *
42
     * @var array
43
     */
44
    protected $appends = ['name', 'url'];
45
46
    /**
47
     * Array of user-editable attributes (excluding machine-generated stuff)
48
     *
49
     * @static array
50
     */
51
    public static $editableAttributes = [
52
        'lastname', 'firstname', 'phone', 'email', 'lang', 'note'
53
    ];
54
55
    /**
56
     * Find user from some identifier (Alma primary id, barcode or other).
57
     *
58
     * @param string $identifier
59
     * @return User|null
60
     */
61
    public static function fromIdentifier($identifier)
62
    {
63
        if (empty($identifier)) {
64
            return null;
65
        }
66
        $user = User::where('alma_primary_id', '=', $identifier)->first();
67
        if (is_null($user)) {
68
            $user = User::whereHas('identifiers', function (Builder $query) use ($identifier) {
69
                $query->where('value', '=', $identifier);
70
            })->first();
71
        }
72
73
        return $user;
74
    }
75
76
    public function identifiers()
77
    {
78
        return $this->hasMany(UserIdentifier::class);
79
    }
80
81
    public function getAllIdentifierValues()
82
    {
83
        $values = [];
84
        if ($this->alma_primary_id) {
85
            $values[] = $this->alma_primary_id;
86
        }
87
        foreach ($this->identifiers as $identifier) {
88
            $values[] = $identifier['value'];
89
        }
90
        return $values;
91
    }
92
93
    public function loans()
94
    {
95
        return $this->hasMany(Loan::class);
96
    }
97
98
    public function deliveredLoans()
99
    {
100
        return $this->hasMany(Loan::class)
101
            ->whereNotNull('deleted_at')
102
            ->with('item.thing')
103
            ->withTrashed()
104
            ->orderBy('created_at', 'desc');
105
    }
106
107
    public function getNameAttribute()
108
    {
109
        return $this->lastname . ', ' . $this->firstname;
110
    }
111
112
    public function getUrlAttribute()
113
    {
114
        return action('UsersController@getShow', $this->id);
0 ignored issues
show
Bug introduced by
The function action was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

114
        return /** @scrutinizer ignore-call */ action('UsersController@getShow', $this->id);
Loading history...
115
    }
116
117
    protected function mergeAttribute($key, User $user)
118
    {
119
        return strlen($user->$key) > strlen($this->$key) ? $user->$key : $this->$key;
120
    }
121
122
    /**
123
     * Get data for merging $user into the current user. The returned
124
     * array can be passed directly to mergeWith or presented to a user
125
     * for review first.
126
     *
127
     * @param  User  $user
128
     * @return array
129
     */
130
    public function getMergeData($user)
131
    {
132
        $merged = array();
133
        foreach (static::$editableAttributes as $attr) {
134
            $merged[$attr] = $this->mergeAttribute($attr, $user);
135
        }
136
        $merged['identifiers'] = [];
137
        foreach ($this->identifiers()->get(['type', 'value']) as $identifier) {
138
            $merged['identifiers'][] = $identifier;
139
        }
140
        foreach ($user->identifiers()->get(['type', 'value']) as $identifier) {
141
            $merged['identifiers'][] = $identifier;
142
        }
143
        return $merged;
144
    }
145
146
    /**
147
     * Merge in another user $user
148
     *
149
     * @param  User  $user
150
     * @param  array  $data  An array of merged attributes (optional)
151
     * @return \Illuminate\Support\MessageBag
152
     */
153
    public function merge(User $user, array $data = null)
154
    {
155
156
        if (is_null($data)) {
157
            $data = $this->getMergeData($user);
158
        }
159
160
        // Validate
161
        $errors = new MessageBag();
162
163
        // if (!empty($ltid) && !empty($user->ltid) && ($ltid != $user->ltid)) {
164
        //  $errors->add('ltid_conflict', "Kan ikke flette nytt LTID $ltid med eksisterende $user->ltid.");
165
        // }
166
167
        // if (!empty($ltid) && !empty($this->ltid) && ($ltid != $this->ltid)) {
168
        //  $errors->add('ltid_conflict', "Kan ikke flette nytt LTID $ltid med eksisterende $this->ltid.");
169
        // }
170
171
        if ($errors->count() > 0) {
172
            return $errors;
173
        }
174
175
        \Log::info('Slo sammen to brukere (ID ' . $user->id . ' og ' . $this->id . ')');
176
177
        foreach ($user->loans as $loan) {
178
            $loan->user_id = $this->id;
179
            $loan->save();
180
            \Log::info('Lån ' . $loan->id . ' flyttet fra bruker ' . $user->id . ' til ' . $this->id);
181
        }
182
183
        // Delete other user first to avoid database integrity conflicts
184
        $user->delete();
185
186
        // Update properties of the current user with merge data
187
        foreach ($data as $key => $val) {
188
            if ($key != 'identifiers') {
189
                $this->$key = $val;
190
            }
191
        }
192
193
        $this->save();
194
195
        $this->setIdentifiers($data['identifiers']);
196
197
        return null;
198
    }
199
200
    public function hasFees()
201
    {
202
        return $this->fees !== 0;
203
    }
204
205
    /**
206
     * Update unique value. If the value clashes with another user, delete the other user if it has no loans.
207
     *
208
     * @param array $identifiers
209
     * @param bool $deleteOnConflict
210
     */
211
    public function setIdentifiers(array $identifiers, bool $deleteOnConflict = false)
212
    {
213
        $currentValues = $this->identifiers->pluck('value')->toArray();
214
215
        $newIdentifiers = [];
216
        foreach ($identifiers as $identifier) {
217
            $newIdentifiers[$identifier['value']] = $identifier['type'];
218
        }
219
220
        $newValues = array_keys($newIdentifiers);
221
222
        $valuesToRemove = array_diff($currentValues, $newValues);
223
        $valuesToAdd = array_diff($newValues, $currentValues);
224
225
        $toAdd = array_map(function ($value) use ($newIdentifiers) {
226
            return [
227
                'user_id' => $this->id,
228
                'value' => $value,
229
                'type' => $newIdentifiers[$value],
230
            ];
231
        }, $valuesToAdd);
232
233
        // Check uniqueness
234
        foreach ($toAdd as $identifier) {
235
            $model = UserIdentifier::where('value', '=', $identifier['value'])->first();
236
            if (!is_null($model) && $model->user_id !== $this->id) {
237
                if ($deleteOnConflict) {
238
                    $this->deleteOtherUserIfPossible($model->user, $identifier['value']);
239
                } else {
240
                    throw new \RuntimeException(
241
                        "ID-konflikt for verdien {$identifier['value']}, og kan ikke slette {$model->user->id}."
242
                    );
243
                }
244
            }
245
        }
246
247
        if (count($valuesToRemove) || count($valuesToAdd)) {
248
            $msg = sprintf(
249
                'Oppdaterte identifikatorer for <a href="%s">%s</a>.',
250
                action('UsersController@getShow', $this->id),
0 ignored issues
show
Bug introduced by
The function action was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

250
                /** @scrutinizer ignore-call */ 
251
                action('UsersController@getShow', $this->id),
Loading history...
251
                $this->name
252
            );
253
254
            // Delete
255
            if (count($valuesToRemove)) {
256
                $msg .= sprintf(
257
                    ' Fjernet: %s.',
258
                    implode(', ', $valuesToRemove)
259
                );
260
                UserIdentifier::where('user_id', '=', $this->id)->whereIn('value', $valuesToRemove)->delete();
261
            }
262
263
            // Add
264
            if (count($valuesToAdd)) {
265
                $msg .= sprintf(
266
                    ' La til: %s.',
267
                    implode(', ', $valuesToAdd)
268
                );
269
                UserIdentifier::insert($toAdd);
270
            }
271
272
            \Log::info($msg);
273
        }
274
    }
275
276
    /**
277
     * Set Alma Primary Id. If the value clashes with another user, delete the other user if it has no loans.
278
     *
279
     * @param string $value
280
     * @param bool $deleteOnConflict
281
     */
282
    public function setAlmaPrimaryId(string $value, $deleteOnConflict = false)
283
    {
284
        // Check for uniqueness
285
        if (is_null($this->id)) {
286
            // Model not saved yet
287
            $otherUser = User::where('alma_primary_id', '=', $value)->first();
288
        } else {
289
            $otherUser = User::where('alma_primary_id', '=', $value)->where('id', '!=', $this->id)->first();
290
        }
291
292
        if (!is_null($otherUser)) {
293
            if ($deleteOnConflict) {
294
                $this->deleteOtherUserIfPossible($otherUser, $value);
295
            } else {
296
                throw new \RuntimeException(
297
                    "ID-konflikt for verdien {$value}, og kan ikke slette {$otherUser->id}."
298
                );
299
            }
300
        }
301
302
        $this->alma_primary_id = $value;
0 ignored issues
show
Bug Best Practice introduced by
The property alma_primary_id does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
303
    }
304
305
    protected function deleteOtherUserIfPossible(User $otherUser, string $value)
306
    {
307
        if (!$otherUser->loans->count()) {
308
            if (!is_null($this->id)) {
309
                $localRef = "brukeren med ID {$this->id}";
310
            } else {
311
                $localRef = "(ny bruker)";
312
            }
313
            \Log::warning(
314
                "Verdien '{$value}' er i bruk som identifikator for flere brukere. " .
315
                "Sletter brukeren med ID {$otherUser->id} (som ikke hadde noen lån), beholder $localRef."
316
            );
317
            $otherUser->delete();
318
        } else {
319
            throw new \RuntimeException(
320
                "Verdien '{$value}' er i bruk som identifikator for flere brukere. ".
321
                "Kan ikke slette brukeren {$otherUser->id} fordi brukeren har lån."
322
            );
323
        }
324
    }
325
}
326