User::getAllIdentifierValues()   A
last analyzed

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 DateTimeInterface;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Foundation\Auth\User as Authenticatable;
8
use Illuminate\Notifications\Notifiable;
9
use Illuminate\Support\MessageBag;
10
11
class User extends Authenticatable
12
{
13
14
    use Notifiable;
0 ignored issues
show
Bug introduced by
The trait Illuminate\Notifications\Notifiable requires the property $email which is not provided by App\User.
Loading history...
15
16
    /**
17
     * The attributes that are mass assignable.
18
     *
19
     * @var array
20
     */
21
    protected $fillable = ['in_alma', 'firstname', 'lastname', 'phone', 'email', 'lang'];
22
23
    /**
24
     * The attributes that should be cast to native types.
25
     *
26
     * @var array
27
     */
28
    protected $casts = [
29
        'blocks' => 'array',
30
        'fees' => 'integer',
31
    ];
32
33
   /**
34
     * The attributes that should be mutated to dates.
35
     *
36
     * @var array
37
     */
38
    protected $dates = ['last_loan_at'];
39
40
    /**
41
     * The accessors to append to the model's array form.
42
     *
43
     * @var array
44
     */
45
    protected $appends = ['name', 'url'];
46
47
    /**
48
     * Array of user-editable attributes (excluding machine-generated stuff)
49
     *
50
     * @static array
51
     */
52
    public static $editableAttributes = [
53
        'lastname', 'firstname', 'phone', 'email', 'lang', 'note'
54
    ];
55
56
    /**
57
     * Prepare a date for array / JSON serialization.
58
     *
59
     * @param  \DateTimeInterface  $date
60
     * @return string
61
     */
62
    protected function serializeDate(DateTimeInterface $date)
63
    {
64
        return $date->format('Y-m-d H:i:s');
65
    }
66
67
    /**
68
     * Find user from some identifier (Alma primary id, barcode or other).
69
     *
70
     * @param string $identifier
71
     * @return User|null
72
     */
73
    public static function fromIdentifier($identifier)
74
    {
75
        if (empty($identifier)) {
76
            return null;
77
        }
78
        $user = User::where('alma_primary_id', '=', $identifier)->first();
79
        if (is_null($user)) {
80
            $user = User::whereHas('identifiers', function (Builder $query) use ($identifier) {
81
                $query->where('value', '=', $identifier);
82
            })->first();
83
        }
84
85
        return $user;
86
    }
87
88
    public function identifiers()
89
    {
90
        return $this->hasMany(UserIdentifier::class);
91
    }
92
93
    public function getAllIdentifierValues()
94
    {
95
        $values = [];
96
        if ($this->alma_primary_id) {
97
            $values[] = $this->alma_primary_id;
98
        }
99
        foreach ($this->identifiers as $identifier) {
100
            $values[] = $identifier['value'];
101
        }
102
        return $values;
103
    }
104
105
    public function loans()
106
    {
107
        return $this->hasMany(Loan::class);
108
    }
109
110
    public function deliveredLoans()
111
    {
112
        return $this->hasMany(Loan::class)
113
            ->whereNotNull('deleted_at')
114
            ->with('item.thing')
115
            ->withTrashed()
116
            ->orderBy('created_at', 'desc');
117
    }
118
119
    public function getNameAttribute()
120
    {
121
        return $this->lastname . ', ' . $this->firstname;
122
    }
123
124
    public function getUrlAttribute()
125
    {
126
        return action('UsersController@getShow', $this->id);
127
    }
128
129
    protected function mergeAttribute($key, User $user)
130
    {
131
        return strlen($user->$key) > strlen($this->$key) ? $user->$key : $this->$key;
132
    }
133
134
    /**
135
     * Get data for merging $user into the current user. The returned
136
     * array can be passed directly to mergeWith or presented to a user
137
     * for review first.
138
     *
139
     * @param  User  $user
140
     * @return array
141
     */
142
    public function getMergeData($user)
143
    {
144
        $merged = array();
145
        foreach (static::$editableAttributes as $attr) {
146
            $merged[$attr] = $this->mergeAttribute($attr, $user);
147
        }
148
        $merged['identifiers'] = [];
149
        foreach ($this->identifiers()->get(['type', 'value']) as $identifier) {
150
            $merged['identifiers'][] = $identifier;
151
        }
152
        foreach ($user->identifiers()->get(['type', 'value']) as $identifier) {
153
            $merged['identifiers'][] = $identifier;
154
        }
155
        return $merged;
156
    }
157
158
    /**
159
     * Merge in another user $user
160
     *
161
     * @param  User  $user
162
     * @param  array  $data  An array of merged attributes (optional)
163
     * @return \Illuminate\Support\MessageBag
164
     */
165
    public function merge(User $user, array $data = null)
166
    {
167
168
        if (is_null($data)) {
169
            $data = $this->getMergeData($user);
170
        }
171
172
        // Validate
173
        $errors = new MessageBag();
174
175
        // if (!empty($ltid) && !empty($user->ltid) && ($ltid != $user->ltid)) {
176
        //  $errors->add('ltid_conflict', "Kan ikke flette nytt LTID $ltid med eksisterende $user->ltid.");
177
        // }
178
179
        // if (!empty($ltid) && !empty($this->ltid) && ($ltid != $this->ltid)) {
180
        //  $errors->add('ltid_conflict', "Kan ikke flette nytt LTID $ltid med eksisterende $this->ltid.");
181
        // }
182
183
        if ($errors->count() > 0) {
184
            return $errors;
185
        }
186
187
        \Log::info('Slo sammen to brukere (ID ' . $user->id . ' og ' . $this->id . ')');
188
189
        foreach ($user->loans as $loan) {
190
            $loan->user_id = $this->id;
191
            $loan->save();
192
            \Log::info('Lån ' . $loan->id . ' flyttet fra bruker ' . $user->id . ' til ' . $this->id);
193
        }
194
195
        // Delete other user first to avoid database integrity conflicts
196
        $user->delete();
197
198
        // Update properties of the current user with merge data
199
        foreach ($data as $key => $val) {
200
            if ($key != 'identifiers') {
201
                $this->$key = $val;
202
            }
203
        }
204
205
        $this->save();
206
207
        $this->setIdentifiers($data['identifiers']);
208
209
        return null;
210
    }
211
212
    public function hasFees()
213
    {
214
        return $this->fees !== 0;
215
    }
216
217
    /**
218
     * Update unique value. If the value clashes with another user, delete the other user if it has no loans.
219
     *
220
     * @param array $identifiers
221
     * @param bool $deleteOnConflict
222
     */
223
    public function setIdentifiers(array $identifiers, bool $deleteOnConflict = false)
224
    {
225
        $currentValues = $this->identifiers->pluck('value')->toArray();
226
227
        $newIdentifiers = [];
228
        foreach ($identifiers as $identifier) {
229
            $newIdentifiers[$identifier['value']] = $identifier['type'];
230
        }
231
232
        $newValues = array_keys($newIdentifiers);
233
234
        $valuesToRemove = array_diff($currentValues, $newValues);
235
        $valuesToAdd = array_diff($newValues, $currentValues);
236
237
        $toAdd = array_map(function ($value) use ($newIdentifiers) {
238
            return [
239
                'user_id' => $this->id,
240
                'value' => $value,
241
                'type' => $newIdentifiers[$value],
242
            ];
243
        }, $valuesToAdd);
244
245
        // Check uniqueness
246
        foreach ($toAdd as $identifier) {
247
            $model = UserIdentifier::where('value', '=', $identifier['value'])->first();
248
            if (!is_null($model) && $model->user_id !== $this->id) {
249
                if ($deleteOnConflict) {
250
                    $this->deleteOtherUserIfPossible($model->user, $identifier['value']);
251
                } else {
252
                    throw new \RuntimeException(
253
                        "ID-konflikt for verdien {$identifier['value']}, og kan ikke slette {$model->user->id}."
254
                    );
255
                }
256
            }
257
        }
258
259
        if (count($valuesToRemove) || count($valuesToAdd)) {
260
            $msg = sprintf(
261
                'Oppdaterte identifikatorer for <a href="%s">%s</a>.',
262
                action('UsersController@getShow', $this->id),
263
                $this->name
264
            );
265
266
            // Delete
267
            if (count($valuesToRemove)) {
268
                $msg .= sprintf(
269
                    ' Fjernet: %s.',
270
                    implode(', ', $valuesToRemove)
271
                );
272
                UserIdentifier::where('user_id', '=', $this->id)->whereIn('value', $valuesToRemove)->delete();
273
            }
274
275
            // Add
276
            if (count($valuesToAdd)) {
277
                $msg .= sprintf(
278
                    ' La til: %s.',
279
                    implode(', ', $valuesToAdd)
280
                );
281
                UserIdentifier::insert($toAdd);
282
            }
283
284
            \Log::info($msg);
285
        }
286
    }
287
288
    /**
289
     * Set Alma Primary Id. If the value clashes with another user, delete the other user if it has no loans.
290
     *
291
     * @param string $value
292
     * @param bool $deleteOnConflict
293
     */
294
    public function setAlmaPrimaryId(string $value, $deleteOnConflict = false)
295
    {
296
        // Check for uniqueness
297
        if (is_null($this->id)) {
0 ignored issues
show
introduced by
The condition is_null($this->id) is always false.
Loading history...
298
            // Model not saved yet
299
            $otherUser = User::where('alma_primary_id', '=', $value)->first();
300
        } else {
301
            $otherUser = User::where('alma_primary_id', '=', $value)->where('id', '!=', $this->id)->first();
302
        }
303
304
        if (!is_null($otherUser)) {
305
            if ($deleteOnConflict) {
306
                $this->deleteOtherUserIfPossible($otherUser, $value);
307
            } else {
308
                throw new \RuntimeException(
309
                    "ID-konflikt for verdien {$value}, og kan ikke slette {$otherUser->id}."
310
                );
311
            }
312
        }
313
314
        $this->alma_primary_id = $value;
0 ignored issues
show
Bug introduced by
The property alma_primary_id does not seem to exist on App\User. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
315
    }
316
317
    protected function deleteOtherUserIfPossible(User $otherUser, string $value)
318
    {
319
        if (!$otherUser->loans->count()) {
320
            if (!is_null($this->id)) {
0 ignored issues
show
introduced by
The condition is_null($this->id) is always false.
Loading history...
321
                $localRef = "brukeren med ID {$this->id}";
322
            } else {
323
                $localRef = "(ny bruker)";
324
            }
325
            \Log::warning(
326
                "Verdien '{$value}' er i bruk som identifikator for flere brukere. " .
327
                "Sletter brukeren med ID {$otherUser->id} (som ikke hadde noen lån), beholder $localRef."
328
            );
329
            $otherUser->delete();
330
        } else {
331
            throw new \RuntimeException(
332
                "Verdien '{$value}' er i bruk som identifikator for flere brukere. ".
333
                "Kan ikke slette brukeren {$otherUser->id} fordi brukeren har lån."
334
            );
335
        }
336
    }
337
}
338