Device   F
last analyzed

Complexity

Total Complexity 149

Size/Duplication

Total Lines 821
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 149
eloc 264
c 1
b 0
f 0
dl 0
loc 821
rs 2

98 Methods

Rating   Name   Duplication   Size   Complexity  
A setStatusAttribute() 0 3 1
A setIpAttribute() 0 3 1
A getIpAttribute() 0 7 3
A scopeIsIgnored() 0 5 1
A scopeNotIgnored() 0 4 1
A scopeIsDisabled() 0 4 1
A groups() 0 3 1
A rules() 0 3 1
A sensors() 0 3 1
A netscalerVservers() 0 3 1
A portsFdb() 0 3 1
A packages() 0 3 1
A routes() 0 3 1
A ports() 0 3 1
A processors() 0 3 1
A portsNac() 0 3 1
A parents() 0 3 1
A perf() 0 3 1
A findByHostname() 0 3 1
A applications() 0 3 1
A vrfs() 0 3 1
A mplsServices() 0 3 1
A mplsLsps() 0 3 1
A ospfPorts() 0 3 1
A storage() 0 3 1
A users() 0 4 1
A getIconAttribute() 0 3 1
A scopeNotInServiceTemplate() 0 7 1
A ospfInstances() 0 3 1
A pollerTarget() 0 17 5
A eventlogs() 0 3 1
A isisAdjacencies() 0 3 1
A scopeNotInDeviceGroup() 0 7 1
A scopeWhereUptime() 0 5 1
A isUnderMaintenance() 0 26 4
A scopeInDeviceGroup() 0 7 1
A mplsLspPaths() 0 3 1
A hostResources() 0 3 1
A scopeCanPing() 0 3 1
A ipv4() 0 3 1
A mplsSdps() 0 3 1
A alertSchedules() 0 3 1
A scopeHasAccess() 0 3 1
A mplsTunnelArHops() 0 3 1
B findByIp() 0 41 9
A wirelessSensors() 0 3 1
A printerSupplies() 0 3 1
A scopeIsUp() 0 7 1
A services() 0 3 1
A vlans() 0 3 1
A mempools() 0 3 1
A ipsecTunnels() 0 3 1
A name() 0 10 4
A formatDownUptime() 0 5 2
A syslogs() 0 3 1
A logo() 0 17 3
A alerts() 0 3 1
A shortDisplayName() 0 17 3
A pseudowires() 0 3 1
A attribs() 0 3 1
A rServers() 0 3 1
A ospfNbrs() 0 3 1
A cefSwitching() 0 3 1
A forgetAttrib() 0 16 2
A scopeIsDown() 0 7 1
A muninPlugins() 0 3 1
A scopeIsDisableNotify() 0 4 1
A getAttrib() 0 3 1
A getVrfContexts() 0 3 2
A components() 0 3 1
A scopeWhereAttributeDisabled() 0 8 1
A validateStandalone() 0 9 5
A scopeIsNotDisabled() 0 5 1
A mefInfo() 0 3 1
A vrfLites() 0 3 1
A vServers() 0 3 1
A mplsSdpBinds() 0 3 1
A accessPoints() 0 3 1
A mplsTunnelCHops() 0 3 1
A location() 0 3 1
A updateMaxDepth() 0 21 4
A scopeInServiceTemplate() 0 7 1
A entityPhysical() 0 3 1
C setLocation() 0 26 12
A mplsSaps() 0 3 1
A children() 0 3 1
A graphs() 0 3 1
A serviceTemplates() 0 3 1
A setAttrib() 0 14 2
A bgppeers() 0 3 1
A slas() 0 3 1
A stpInstances() 0 3 1
A displayName() 0 7 4
A vminfo() 0 3 1
A canAccess() 0 11 3
A ipv6() 0 3 1
A getAttribs() 0 3 1
A scopeIsActive() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like Device often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Device, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace App\Models;
4
5
use Fico7489\Laravel\Pivot\Traits\PivotEventTrait;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Database\Eloquent\Factories\HasFactory;
8
use Illuminate\Database\Eloquent\ModelNotFoundException;
9
use Illuminate\Database\Eloquent\Relations\BelongsTo;
10
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
11
use Illuminate\Database\Eloquent\Relations\HasMany;
12
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
13
use Illuminate\Database\Eloquent\Relations\MorphToMany;
14
use Illuminate\Database\Query\JoinClause;
15
use Illuminate\Support\Str;
16
use LibreNMS\Exceptions\InvalidIpException;
17
use LibreNMS\Util\IP;
18
use LibreNMS\Util\IPv4;
19
use LibreNMS\Util\IPv6;
20
use LibreNMS\Util\Rewrite;
21
use LibreNMS\Util\Time;
22
use LibreNMS\Util\Url;
23
use Permissions;
24
25
/**
26
 * @property-read int|null $ports_count
27
 * @property-read int|null $sensors_count
28
 * @property-read int|null $wirelessSensors_count
29
 *
30
 * @method static \Database\Factories\DeviceFactory factory(...$parameters)
31
 */
32
class Device extends BaseModel
33
{
34
    use PivotEventTrait, HasFactory;
35
36
    public $timestamps = false;
37
    protected $primaryKey = 'device_id';
38
    protected $fillable = ['hostname', 'ip', 'status', 'status_reason', 'sysName', 'sysDescr', 'sysObjectID', 'hardware', 'version', 'features', 'serial', 'icon'];
39
    protected $casts = [
40
        'last_polled' => 'datetime',
41
        'status' => 'boolean',
42
    ];
43
44
    // ---- Helper Functions ----
45
46
    public static function findByHostname($hostname)
47
    {
48
        return static::where('hostname', $hostname)->first();
49
    }
50
51
    /**
52
     * Returns IP/Hostname where polling will be targeted to
53
     *
54
     * @param  string|array  $device  hostname which will be triggered
55
     *                                array  $device associative array with device data
56
     * @return string IP/Hostname to which Device polling is targeted
57
     */
58
    public static function pollerTarget($device)
59
    {
60
        if (! is_array($device)) {
61
            $ret = static::where('hostname', $device)->first(['hostname', 'overwrite_ip']);
62
            if (empty($ret)) {
63
                return $device;
64
            }
65
            $overwrite_ip = $ret->overwrite_ip;
66
            $hostname = $ret->hostname;
67
        } elseif (array_key_exists('overwrite_ip', $device)) {
68
            $overwrite_ip = $device['overwrite_ip'];
69
            $hostname = $device['hostname'];
70
        } else {
71
            return $device['hostname'];
72
        }
73
74
        return $overwrite_ip ?: $hostname;
75
    }
76
77
    public static function findByIp($ip)
78
    {
79
        if (! IP::isValid($ip)) {
80
            return null;
81
        }
82
83
        $device = static::where('hostname', $ip)->orWhere('ip', inet_pton($ip))->first();
84
85
        if ($device) {
86
            return $device;
87
        }
88
89
        try {
90
            $ipv4 = new IPv4($ip);
91
            $port = Ipv4Address::where('ipv4_address', (string) $ipv4)
92
                ->with('port', 'port.device')
93
                ->firstOrFail()->port;
0 ignored issues
show
Bug Best Practice introduced by
The property port does not exist on App\Models\Ipv4Address. Since you implemented __get, consider adding a @property annotation.
Loading history...
94
            if ($port) {
95
                return $port->device;
0 ignored issues
show
Bug introduced by
The property device does not seem to exist on Illuminate\Database\Eloquent\Relations\Relation.
Loading history...
96
            }
97
        } catch (InvalidIpException $e) {
98
            //
99
        } catch (ModelNotFoundException $e) {
100
            //
101
        }
102
103
        try {
104
            $ipv6 = new IPv6($ip);
105
            $port = Ipv6Address::where('ipv6_address', $ipv6->uncompressed())
106
                ->with(['port', 'port.device'])
107
                ->firstOrFail()->port;
0 ignored issues
show
Bug Best Practice introduced by
The property port does not exist on App\Models\Ipv6Address. Since you implemented __get, consider adding a @property annotation.
Loading history...
108
            if ($port) {
109
                return $port->device;
110
            }
111
        } catch (InvalidIpException $e) {
112
            //
113
        } catch (ModelNotFoundException $e) {
114
            //
115
        }
116
117
        return null;
118
    }
119
120
    /**
121
     * Get VRF contexts to poll.
122
     * If no contexts are found, return the default context ''
123
     *
124
     * @return array
125
     */
126
    public function getVrfContexts(): array
127
    {
128
        return $this->vrfLites->isEmpty() ? [''] : $this->vrfLites->pluck('context_name')->all();
129
    }
130
131
    /**
132
     * Get the display name of this device (hostname) unless force_ip_to_sysname is set
133
     * and hostname is an IP and sysName is set
134
     *
135
     * @return string
136
     */
137
    public function displayName()
138
    {
139
        if (\LibreNMS\Config::get('force_ip_to_sysname') && $this->sysName && IP::isValid($this->hostname)) {
140
            return $this->sysName;
141
        }
142
143
        return $this->hostname;
144
    }
145
146
    public function name()
147
    {
148
        $displayName = $this->displayName();
149
        if ($this->sysName !== $displayName) {
150
            return $this->sysName;
151
        } elseif ($this->hostname !== $displayName && $this->hostname !== $this->ip) {
152
            return $this->hostname;
153
        }
154
155
        return '';
156
    }
157
158
    public function isUnderMaintenance()
159
    {
160
        if (! $this->device_id) {
161
            return false;
162
        }
163
164
        $query = AlertSchedule::isActive()
165
            ->where(function (Builder $query) {
166
                $query->whereHas('devices', function (Builder $query) {
167
                    $query->where('alert_schedulables.alert_schedulable_id', $this->device_id);
168
                });
169
170
                if ($this->groups->isNotEmpty()) {
171
                    $query->orWhereHas('deviceGroups', function (Builder $query) {
172
                        $query->whereIn('alert_schedulables.alert_schedulable_id', $this->groups->pluck('id'));
173
                    });
174
                }
175
176
                if ($this->location) {
177
                    $query->orWhereHas('locations', function (Builder $query) {
178
                        $query->where('alert_schedulables.alert_schedulable_id', $this->location->id);
179
                    });
180
                }
181
            });
182
183
        return $query->exists();
184
    }
185
186
    /**
187
     * Get the shortened display name of this device.
188
     * Length is always overridden by shorthost_target_length.
189
     *
190
     * @param  int  $length  length to shorten to, will not break up words so may be longer
191
     * @return string
192
     */
193
    public function shortDisplayName($length = 12)
194
    {
195
        $name = $this->displayName();
196
197
        // IP addresses should not be shortened
198
        if (IP::isValid($name)) {
199
            return $name;
200
        }
201
202
        $length = \LibreNMS\Config::get('shorthost_target_length', $length);
203
        if ($length < strlen($name)) {
204
            $take = substr_count($name, '.', 0, $length) + 1;
205
206
            return implode('.', array_slice(explode('.', $name), 0, $take));
207
        }
208
209
        return $name;
210
    }
211
212
    /**
213
     * Check if user can access this device.
214
     *
215
     * @param  User  $user
216
     * @return bool
217
     */
218
    public function canAccess($user)
219
    {
220
        if (! $user) {
0 ignored issues
show
introduced by
$user is of type App\Models\User, thus it always evaluated to true.
Loading history...
221
            return false;
222
        }
223
224
        if ($user->hasGlobalRead()) {
225
            return true;
226
        }
227
228
        return Permissions::canAccessDevice($this->device_id, $user->user_id);
0 ignored issues
show
Bug introduced by
The method canAccessDevice() does not exist on App\Facades\Permissions. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

228
        return Permissions::/** @scrutinizer ignore-call */ canAccessDevice($this->device_id, $user->user_id);
Loading history...
229
    }
230
231
    public function formatDownUptime($short = false)
232
    {
233
        $time = ($this->status == 1) ? $this->uptime : time() - strtotime($this->last_polled);
234
235
        return Time::formatInterval($time, $short);
236
    }
237
238
    /**
239
     * @return string
240
     */
241
    public function logo()
242
    {
243
        $base_name = pathinfo($this->icon, PATHINFO_FILENAME);
244
        $options = [
245
            "images/logos/$base_name.svg",
246
            "images/logos/$base_name.png",
247
            "images/os/$base_name.svg",
248
            "images/os/$base_name.png",
249
        ];
250
251
        foreach ($options as $file) {
252
            if (is_file(public_path() . "/$file")) {
253
                return asset($file);
254
            }
255
        }
256
257
        return asset('images/os/generic.svg');
258
    }
259
260
    /**
261
     * Update the max_depth field based on parents
262
     * Performs SQL query, so make sure all parents are saved first
263
     *
264
     * @param  int  $exclude  exclude a device_id from being considered (used for deleting)
265
     */
266
    public function updateMaxDepth($exclude = null)
267
    {
268
        // optimize for memory instead of time
269
        $query = $this->parents()->getQuery();
270
        if (! is_null($exclude)) {
271
            $query->where('device_id', '!=', $exclude);
272
        }
273
274
        $count = $query->count();
275
        if ($count === 0) {
276
            if ($this->children()->count() === 0) {
277
                $this->max_depth = 0; // no children or parents
278
            } else {
279
                $this->max_depth = 1; // has children
280
            }
281
        } else {
282
            $parents_max_depth = $query->max('max_depth');
283
            $this->max_depth = $parents_max_depth + 1;
284
        }
285
286
        $this->save();
287
    }
288
289
    /**
290
     * Device dependency check to see if this node is standalone or not.
291
     * Standalone is a special case where the device has no parents or children and is denoted by a max_depth of 0
292
     *
293
     * Only checks on root nodes (where max_depth is 1 or 0)
294
     */
295
    public function validateStandalone()
296
    {
297
        if ($this->max_depth === 0 && $this->children()->count() > 0) {
298
            $this->max_depth = 1; // has children
299
        } elseif ($this->max_depth === 1 && $this->parents()->count() === 0) {
300
            $this->max_depth = 0; // no children or parents
301
        }
302
303
        $this->save();
304
    }
305
306
    public function getAttrib($name)
307
    {
308
        return $this->attribs->pluck('attrib_value', 'attrib_type')->get($name);
309
    }
310
311
    public function setAttrib($name, $value)
312
    {
313
        $attrib = $this->attribs->first(function ($item) use ($name) {
314
            return $item->attrib_type === $name;
315
        });
316
317
        if (! $attrib) {
318
            $attrib = new DeviceAttrib(['attrib_type' => $name]);
319
            $this->attribs->push($attrib);
320
        }
321
322
        $attrib->attrib_value = $value;
323
324
        return (bool) $this->attribs()->save($attrib);
325
    }
326
327
    public function forgetAttrib($name)
328
    {
329
        $attrib_index = $this->attribs->search(function ($attrib) use ($name) {
330
            return $attrib->attrib_type === $name;
331
        });
332
333
        if ($attrib_index !== false) {
334
            $deleted = (bool) $this->attribs->get($attrib_index)->delete();
335
            // only forget the attrib_index after delete, otherwise delete() will fail fatally with:
336
            // Symfony\\Component\\Debug\Exception\\FatalThrowableError(code: 0):  Call to a member function delete() on null
337
            $this->attribs->forget((string) $attrib_index);
338
339
            return $deleted;
340
        }
341
342
        return false;
343
    }
344
345
    public function getAttribs()
346
    {
347
        return $this->attribs->pluck('attrib_value', 'attrib_type')->toArray();
348
    }
349
350
    /**
351
     * Update the location to the correct location and update GPS if needed
352
     *
353
     * @param  \App\Models\Location|string  $new_location  location data
354
     * @param  bool  $doLookup  try to lookup the GPS coordinates
355
     */
356
    public function setLocation($new_location, bool $doLookup = false)
357
    {
358
        $new_location = $new_location instanceof Location ? $new_location : new Location(['location' => $new_location]);
359
        $new_location->location = $new_location->location ? Rewrite::location($new_location->location) : null;
360
        $coord = array_filter($new_location->only(['lat', 'lng']));
361
362
        if (! $this->override_sysLocation) {
363
            if (! $new_location->location) { // disassociate if the location name is empty
364
                $this->location()->dissociate();
365
366
                return;
367
            }
368
369
            if (! $this->relationLoaded('location') || optional($this->location)->location !== $new_location->location) {
370
                if (! $new_location->exists) { // don't fetch if new location persisted to the DB, just use it
371
                    $new_location = Location::firstOrCreate(['location' => $new_location->location], $coord);
372
                }
373
                $this->location()->associate($new_location);
374
            }
375
        }
376
377
        // set coordinates
378
        if ($this->location && ! $this->location->fixed_coordinates) {
379
            $this->location->fill($coord);
380
            if ($doLookup && empty($coord)) { // only if requested and coordinates not passed explicitly
381
                $this->location->lookupCoordinates($this->hostname);
382
            }
383
        }
384
    }
385
386
    // ---- Accessors/Mutators ----
387
388
    public function getIconAttribute($icon)
389
    {
390
        return Str::start(Url::findOsImage($this->os, $this->features, $icon), 'images/os/');
391
    }
392
393
    public function getIpAttribute($ip)
394
    {
395
        if (empty($ip)) {
396
            return null;
397
        }
398
        // @ suppresses warning, inet_ntop() returns false if it fails
399
        return @inet_ntop($ip) ?: null;
400
    }
401
402
    public function setIpAttribute($ip)
403
    {
404
        $this->attributes['ip'] = inet_pton($ip);
405
    }
406
407
    public function setStatusAttribute($status)
408
    {
409
        $this->attributes['status'] = (int) $status;
410
    }
411
412
    // ---- Query scopes ----
413
414
    public function scopeIsUp($query)
415
    {
416
        return $query->where([
417
            ['status', '=', 1],
418
            ['ignore', '=', 0],
419
            ['disable_notify', '=', 0],
420
            ['disabled', '=', 0],
421
        ]);
422
    }
423
424
    public function scopeIsActive($query)
425
    {
426
        return $query->where([
427
            ['ignore', '=', 0],
428
            ['disabled', '=', 0],
429
        ]);
430
    }
431
432
    public function scopeIsDown($query)
433
    {
434
        return $query->where([
435
            ['status', '=', 0],
436
            ['disable_notify', '=', 0],
437
            ['ignore', '=', 0],
438
            ['disabled', '=', 0],
439
        ]);
440
    }
441
442
    public function scopeIsIgnored($query)
443
    {
444
        return $query->where([
445
            ['ignore', '=', 1],
446
            ['disabled', '=', 0],
447
        ]);
448
    }
449
450
    public function scopeNotIgnored($query)
451
    {
452
        return $query->where([
453
            ['ignore', '=', 0],
454
        ]);
455
    }
456
457
    public function scopeIsDisabled($query)
458
    {
459
        return $query->where([
460
            ['disabled', '=', 1],
461
        ]);
462
    }
463
464
    public function scopeIsDisableNotify($query)
465
    {
466
        return $query->where([
467
            ['disable_notify', '=', 1],
468
        ]);
469
    }
470
471
    public function scopeIsNotDisabled($query)
472
    {
473
        return $query->where([
474
            ['disable_notify', '=', 0],
475
            ['disabled', '=', 0],
476
        ]);
477
    }
478
479
    public function scopeWhereAttributeDisabled(Builder $query, string $attribute): Builder
480
    {
481
        return $query->leftJoin('devices_attribs', function (JoinClause $query) use ($attribute) {
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->leftJoin(...ion(...) { /* ... */ }) could return the type Illuminate\Database\Query\Builder which is incompatible with the type-hinted return Illuminate\Database\Eloquent\Builder. Consider adding an additional type-check to rule them out.
Loading history...
482
            $query->on('devices.device_id', 'devices_attribs.device_id')
483
                ->where('devices_attribs.attrib_type', $attribute);
484
        })->where(function (Builder $query) {
485
            $query->whereNull('devices_attribs.attrib_value')
486
                ->orWhere('devices_attribs.attrib_value', '!=', 'true');
487
        });
488
    }
489
490
    public function scopeWhereUptime($query, $uptime, $modifier = '<')
491
    {
492
        return $query->where([
493
            ['uptime', '>', 0],
494
            ['uptime', $modifier, $uptime],
495
        ]);
496
    }
497
498
    public function scopeCanPing(Builder $query): Builder
499
    {
500
        return $this->scopeWhereAttributeDisabled($query->where('disabled', 0), 'override_icmp_disable');
501
    }
502
503
    public function scopeHasAccess($query, User $user)
504
    {
505
        return $this->hasDeviceAccess($query, $user);
506
    }
507
508
    public function scopeInDeviceGroup($query, $deviceGroup)
509
    {
510
        return $query->whereIn(
511
            $query->qualifyColumn('device_id'), function ($query) use ($deviceGroup) {
512
                $query->select('device_id')
513
                    ->from('device_group_device')
514
                    ->where('device_group_id', $deviceGroup);
515
            }
516
        );
517
    }
518
519
    public function scopeNotInDeviceGroup($query, $deviceGroup)
520
    {
521
        return $query->whereNotIn(
522
            $query->qualifyColumn('device_id'), function ($query) use ($deviceGroup) {
523
                $query->select('device_id')
524
                    ->from('device_group_device')
525
                    ->where('device_group_id', $deviceGroup);
526
            }
527
        );
528
    }
529
530
    public function scopeInServiceTemplate($query, $serviceTemplate)
531
    {
532
        return $query->whereIn(
533
            $query->qualifyColumn('device_id'), function ($query) use ($serviceTemplate) {
534
                $query->select('device_id')
535
                    ->from('service_templates_device')
536
                    ->where('service_template_id', $serviceTemplate);
537
            }
538
        );
539
    }
540
541
    public function scopeNotInServiceTemplate($query, $serviceTemplate)
542
    {
543
        return $query->whereNotIn(
544
            $query->qualifyColumn('device_id'), function ($query) use ($serviceTemplate) {
545
                $query->select('device_id')
546
                    ->from('service_templates_device')
547
                    ->where('service_template_id', $serviceTemplate);
548
            }
549
        );
550
    }
551
552
    // ---- Define Relationships ----
553
554
    public function accessPoints(): HasMany
555
    {
556
        return $this->hasMany(AccessPoint::class, 'device_id');
557
    }
558
559
    public function alerts(): HasMany
560
    {
561
        return $this->hasMany(\App\Models\Alert::class, 'device_id');
562
    }
563
564
    public function attribs(): HasMany
565
    {
566
        return $this->hasMany(\App\Models\DeviceAttrib::class, 'device_id');
567
    }
568
569
    public function alertSchedules(): MorphToMany
570
    {
571
        return $this->morphToMany(\App\Models\AlertSchedule::class, 'alert_schedulable', 'alert_schedulables', 'schedule_id', 'schedule_id');
572
    }
573
574
    public function applications(): HasMany
575
    {
576
        return $this->hasMany(\App\Models\Application::class, 'device_id');
577
    }
578
579
    public function bgppeers(): HasMany
580
    {
581
        return $this->hasMany(\App\Models\BgpPeer::class, 'device_id');
582
    }
583
584
    public function cefSwitching(): HasMany
585
    {
586
        return $this->hasMany(\App\Models\CefSwitching::class, 'device_id');
587
    }
588
589
    public function children(): BelongsToMany
590
    {
591
        return $this->belongsToMany(self::class, 'device_relationships', 'parent_device_id', 'child_device_id');
592
    }
593
594
    public function components(): HasMany
595
    {
596
        return $this->hasMany(\App\Models\Component::class, 'device_id');
597
    }
598
599
    public function hostResources(): HasMany
600
    {
601
        return $this->hasMany(HrDevice::class, 'device_id');
602
    }
603
604
    public function entityPhysical(): HasMany
605
    {
606
        return $this->hasMany(EntPhysical::class, 'device_id');
607
    }
608
609
    public function eventlogs(): HasMany
610
    {
611
        return $this->hasMany(\App\Models\Eventlog::class, 'device_id', 'device_id');
612
    }
613
614
    public function graphs(): HasMany
615
    {
616
        return $this->hasMany(\App\Models\DeviceGraph::class, 'device_id');
617
    }
618
619
    public function groups(): BelongsToMany
620
    {
621
        return $this->belongsToMany(\App\Models\DeviceGroup::class, 'device_group_device', 'device_id', 'device_group_id');
622
    }
623
624
    public function ipsecTunnels(): HasMany
625
    {
626
        return $this->hasMany(IpsecTunnel::class, 'device_id');
627
    }
628
629
    public function ipv4(): HasManyThrough
630
    {
631
        return $this->hasManyThrough(\App\Models\Ipv4Address::class, \App\Models\Port::class, 'device_id', 'port_id', 'device_id', 'port_id');
632
    }
633
634
    public function ipv6(): HasManyThrough
635
    {
636
        return $this->hasManyThrough(\App\Models\Ipv6Address::class, \App\Models\Port::class, 'device_id', 'port_id', 'device_id', 'port_id');
637
    }
638
639
    public function location(): BelongsTo
640
    {
641
        return $this->belongsTo(\App\Models\Location::class, 'location_id', 'id');
642
    }
643
644
    public function mefInfo(): HasMany
645
    {
646
        return $this->hasMany(MefInfo::class, 'device_id');
647
    }
648
649
    public function muninPlugins(): HasMany
650
    {
651
        return $this->hasMany(\App\Models\MuninPlugin::class, 'device_id');
652
    }
653
654
    public function ospfInstances(): HasMany
655
    {
656
        return $this->hasMany(\App\Models\OspfInstance::class, 'device_id');
657
    }
658
659
    public function ospfNbrs(): HasMany
660
    {
661
        return $this->hasMany(\App\Models\OspfNbr::class, 'device_id');
662
    }
663
664
    public function ospfPorts(): HasMany
665
    {
666
        return $this->hasMany(\App\Models\OspfPort::class, 'device_id');
667
    }
668
669
    public function isisAdjacencies(): HasMany
670
    {
671
        return $this->hasMany(\App\Models\IsisAdjacency::class, 'device_id', 'device_id');
672
    }
673
674
    public function netscalerVservers(): HasMany
675
    {
676
        return $this->hasMany(NetscalerVserver::class, 'device_id');
677
    }
678
679
    public function packages(): HasMany
680
    {
681
        return $this->hasMany(\App\Models\Package::class, 'device_id', 'device_id');
682
    }
683
684
    public function parents(): BelongsToMany
685
    {
686
        return $this->belongsToMany(self::class, 'device_relationships', 'child_device_id', 'parent_device_id');
687
    }
688
689
    public function perf(): HasMany
690
    {
691
        return $this->hasMany(\App\Models\DevicePerf::class, 'device_id');
692
    }
693
694
    public function ports(): HasMany
695
    {
696
        return $this->hasMany(\App\Models\Port::class, 'device_id', 'device_id');
697
    }
698
699
    public function portsFdb(): HasMany
700
    {
701
        return $this->hasMany(\App\Models\PortsFdb::class, 'device_id', 'device_id');
702
    }
703
704
    public function portsNac(): HasMany
705
    {
706
        return $this->hasMany(\App\Models\PortsNac::class, 'device_id', 'device_id');
707
    }
708
709
    public function processors(): HasMany
710
    {
711
        return $this->hasMany(\App\Models\Processor::class, 'device_id');
712
    }
713
714
    public function routes(): HasMany
715
    {
716
        return $this->hasMany(Route::class, 'device_id');
717
    }
718
719
    public function rules(): BelongsToMany
720
    {
721
        return $this->belongsToMany(\App\Models\AlertRule::class, 'alert_device_map', 'device_id', 'rule_id');
722
    }
723
724
    public function sensors(): HasMany
725
    {
726
        return $this->hasMany(\App\Models\Sensor::class, 'device_id');
727
    }
728
729
    public function serviceTemplates(): BelongsToMany
730
    {
731
        return $this->belongsToMany(\App\Models\ServiceTemplate::class, 'service_templates_device', 'device_id', 'service_template_id');
732
    }
733
734
    public function services(): HasMany
735
    {
736
        return $this->hasMany(\App\Models\Service::class, 'device_id');
737
    }
738
739
    public function storage(): HasMany
740
    {
741
        return $this->hasMany(\App\Models\Storage::class, 'device_id');
742
    }
743
744
    public function stpInstances(): HasMany
745
    {
746
        return $this->hasMany(Stp::class, 'device_id');
747
    }
748
749
    public function mempools(): HasMany
750
    {
751
        return $this->hasMany(\App\Models\Mempool::class, 'device_id');
752
    }
753
754
    public function mplsLsps(): HasMany
755
    {
756
        return $this->hasMany(\App\Models\MplsLsp::class, 'device_id');
757
    }
758
759
    public function mplsLspPaths(): HasMany
760
    {
761
        return $this->hasMany(\App\Models\MplsLspPath::class, 'device_id');
762
    }
763
764
    public function mplsSdps(): HasMany
765
    {
766
        return $this->hasMany(\App\Models\MplsSdp::class, 'device_id');
767
    }
768
769
    public function mplsServices(): HasMany
770
    {
771
        return $this->hasMany(\App\Models\MplsService::class, 'device_id');
772
    }
773
774
    public function mplsSaps(): HasMany
775
    {
776
        return $this->hasMany(\App\Models\MplsSap::class, 'device_id');
777
    }
778
779
    public function mplsSdpBinds(): HasMany
780
    {
781
        return $this->hasMany(\App\Models\MplsSdpBind::class, 'device_id');
782
    }
783
784
    public function mplsTunnelArHops(): HasMany
785
    {
786
        return $this->hasMany(\App\Models\MplsTunnelArHop::class, 'device_id');
787
    }
788
789
    public function mplsTunnelCHops(): HasMany
790
    {
791
        return $this->hasMany(\App\Models\MplsTunnelCHop::class, 'device_id');
792
    }
793
794
    public function printerSupplies(): HasMany
795
    {
796
        return $this->hasMany(PrinterSupply::class, 'device_id');
797
    }
798
799
    public function pseudowires(): HasMany
800
    {
801
        return $this->hasMany(Pseudowire::class, 'device_id');
802
    }
803
804
    public function rServers(): HasMany
805
    {
806
        return $this->hasMany(LoadbalancerRserver::class, 'device_id');
807
    }
808
809
    public function slas(): HasMany
810
    {
811
        return $this->hasMany(Sla::class, 'device_id');
812
    }
813
814
    public function syslogs(): HasMany
815
    {
816
        return $this->hasMany(\App\Models\Syslog::class, 'device_id', 'device_id');
817
    }
818
819
    public function users(): BelongsToMany
820
    {
821
        // FIXME does not include global read
822
        return $this->belongsToMany(\App\Models\User::class, 'devices_perms', 'device_id', 'user_id');
823
    }
824
825
    public function vminfo(): HasMany
826
    {
827
        return $this->hasMany(\App\Models\Vminfo::class, 'device_id');
828
    }
829
830
    public function vlans(): HasMany
831
    {
832
        return $this->hasMany(\App\Models\Vlan::class, 'device_id');
833
    }
834
835
    public function vrfLites(): HasMany
836
    {
837
        return $this->hasMany(\App\Models\VrfLite::class, 'device_id');
838
    }
839
840
    public function vrfs(): HasMany
841
    {
842
        return $this->hasMany(\App\Models\Vrf::class, 'device_id');
843
    }
844
845
    public function vServers(): HasMany
846
    {
847
        return $this->hasMany(LoadbalancerVserver::class, 'device_id');
848
    }
849
850
    public function wirelessSensors(): HasMany
851
    {
852
        return $this->hasMany(\App\Models\WirelessSensor::class, 'device_id');
853
    }
854
}
855