Passed
Push — master ( 5d0db5...ea9eab )
by Jonathan
11:13
created

Uccello::getRecordByUuid()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 10
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
namespace Uccello\Core\Helpers;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Support\Facades\Auth;
7
use Illuminate\Support\Facades\Cache;
8
use Uccello\Core\Models\Domain;
9
use Uccello\Core\Models\Module;
10
use Uccello\Core\Models\Uitype;
11
use Uccello\Core\Models\Displaytype;
12
use Uccello\Core\Models\Capability;
13
use Uccello\Core\Models\Entity;
14
use Uccello\Core\Models\Filter;
15
16
class Uccello
17
{
18
    /**
19
     * Returns true if multi domains are used, false else.
20
     *
21
     * @return void
22
     */
23
    public function useMultiDomains()
24
    {
25
        return env('UCCELLO_MULTI_DOMAINS', true) !== false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return env('UCCELLO_MULT...MAINS', true) !== false returns the type boolean which is incompatible with the documented return type void.
Loading history...
26
    }
27
28
    /**
29
     * Retrieve prefix and translate the given message.
30
     * If the translation does not exist try to find a default one.
31
     * If no translation exists display only the key.
32
     *
33
     * Priority:
34
     * 1 - Translation overrided in app
35
     * 2 - Translation in package
36
     * 3 - Default translation overrided in app
37
     * 4 - Default translation in uccello
38
     * 5 - No translation
39
     *
40
     * @param  string  $key
41
     * @param  Module|null  $module
42
     * @param  array   $replace
43
     * @param  string  $locale
44
     * @return \Illuminate\Contracts\Translation\Translator|string|array|null
45
     */
46
    public function trans($key = null, ?Module $module = null, $replace = [ ], $locale = null)
47
    {
48
        $translator = app('translator');
49
50
        if (is_null($key)) {
51
            return $translator;
52
        }
53
54
        // If $module is an instance of Module class, add a prefix before the key
55
        if (!is_null($module) && Module::class == get_class($module))
56
        {
57
            // By default prefix is same as the module's name
58
            $prefix = $module->name.'.';
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on Uccello\Core\Models\Module. 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...
59
60
            // 1. Get translation in app
61
            $translation = $translator->trans($prefix.$key, $replace, $locale);
62
63
            if ($translation !== $prefix.$key) {
64
                return $translation;
65
            }
66
67
            // 2. Get translation in package
68
            if (!empty($module->package)) {
69
                // If a package name is defined add it before
70
                $prefix = $module->package.'::'.$prefix;
71
72
                $translation = $translator->trans($prefix.$key, $replace, $locale);
73
                if ($translation !== $prefix.$key) {
74
                    return $translation;
75
                }
76
            }
77
78
            // 3. Try with default translation in app
79
            $appDefaultTranslation = $translator->trans('default.'.$key, $replace, $locale);
80
            if ($appDefaultTranslation !== 'default.'.$key) { // If default translation exists then use it
81
                return $appDefaultTranslation;
82
            }
83
84
            // 4. Try with default translation in uccello
85
            $uccelloDefaultTranslation = $translator->trans('uccello::default.'.$key, $replace, $locale);
86
            if ($uccelloDefaultTranslation !== 'uccello::default.'.$key) { // If default translation exists then use it
87
                return $uccelloDefaultTranslation;
88
            }
89
90
            // 5. If translation does not exist, display only the key
91
            return $key;
92
        }
93
94
        // Default behaviour
95
        return $translator->trans($key, $replace, $locale);
96
    }
97
98
    /**
99
     * Detects which view it must use and returns the evaluated view contents.
100
     *
101
     * Priority:
102
     * 1 - Module view overrided in app
103
     * 2 - Default view overrided in app
104
     * 3 - Module view ovverrided in package
105
     * 4 - Default view defined in package
106
     * 5 - Module view ovverrided in uccello
107
     * 6 - Default view defined in uccello
108
     * 7 - Fallback view if defined
109
     *
110
     * @param string $package
111
     * @param Module $module
112
     * @param string $viewName
113
     * @param string|null $fallbackView
114
     * @return string|null
115
     */
116
    public function view(string $package, Module $module, string $viewName, ?string $fallbackView = null): ?string
117
    {
118
        // Module view overrided in app
119
        $appModuleView = 'uccello.modules.'.$module->name.'.'.$viewName;
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on Uccello\Core\Models\Module. 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...
120
121
        // Default view overrided in app
122
        $appDefaultView = 'uccello.modules.default.'.$viewName;
123
124
        // Module view ovverrided in package
125
        $packageModuleView = $package.'::modules.'.$module->name.'.'.$viewName;
126
127
        // Default view defined in package
128
        $packageDefaultView = $package.'::modules.default.'.$viewName;
129
130
        // Module view ovverrided in uccello
131
        $uccelloModuleView = 'uccello::modules.'.$module->name.'.'.$viewName;
132
133
        // Default view defined in uccello
134
        $uccelloDefaultView = 'uccello::modules.default.'.$viewName;
135
136
        $viewToInclude = null;
137
        if (view()->exists($appModuleView)) {
138
            $viewToInclude = $appModuleView;
139
        } elseif (view()->exists($appDefaultView)) {
140
            $viewToInclude = $appDefaultView;
141
        } elseif (view()->exists($packageModuleView)) {
142
            $viewToInclude = $packageModuleView;
143
        } elseif (view()->exists($packageDefaultView)) {
144
            $viewToInclude = $packageDefaultView;
145
        } elseif (view()->exists($uccelloModuleView)) {
146
            $viewToInclude = $uccelloModuleView;
147
        } elseif (view()->exists($uccelloDefaultView)) {
148
            $viewToInclude = $uccelloDefaultView;
149
        } elseif (!is_null($fallbackView)) {
150
            $viewToInclude = $fallbackView;
151
        }
152
153
        return $viewToInclude;
154
    }
155
156
    /**
157
     * Makes route automaticaly and add module parameter.
158
     *
159
     * @param array|string $name
160
     * @param Domain|string|null $domain
161
     * @param Module|string|null $module
162
     * @param mixed $parameters
163
     * @param boolean $absolute
164
     * @return string
165
     */
166
    public function route($name, $domain = null, $module = null, $parameters = [ ], $absolute = true) : string
167
    {
168
        if (is_a($domain, Domain::class)) {
169
            $domain = $domain->slug;
170
        } else {
171
            $domain = $this->getDomain($domain)->slug ?? null;
172
        }
173
174
        if (is_a($module, Module::class)) {
175
            $module = $module->name;
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on Uccello\Core\Models\Module. 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...
176
        } else {
177
            $module = $this->getModule($module)->name ?? null;
178
        }
179
180
        // Get route uri to check if domain and module parameters are needed
181
        $routeUri = \Route::getRoutes()->getByName($name)->uri ?? null;
0 ignored issues
show
Bug introduced by
It seems like $name can also be of type array; however, parameter $name of Illuminate\Routing\RouteCollection::getByName() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

181
        $routeUri = \Route::getRoutes()->getByName(/** @scrutinizer ignore-type */ $name)->uri ?? null;
Loading history...
182
183
        // Add domain to route if we use multi domains and if the parameter is needed
184
        if (!is_null($domain) && uccello()->useMultiDomains() && preg_match('`{domain}`', $routeUri)) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of uccello() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
185
            $parameters[ 'domain' ] = $domain;
186
        }
187
188
        // Add module to route if the parameter is needed
189
        if (!is_null($module) && preg_match('`{module}`', $routeUri)) {
190
            $parameters[ 'module' ] = $module;
191
        }
192
193
        return route($name, $parameters, $absolute);
194
    }
195
196
    /**
197
     * Returns the list of capabilities.
198
     *
199
     * @return \Illuminate\Database\Eloquent\Collection
200
     *
201
     * @see Uccello\Core\Models\Permission
202
     */
203
    public function getCapabilities(): Collection
204
    {
205
        return Capability::all();
206
    }
207
208
    /**
209
     * Get a domain instance by slug or id
210
     *
211
     * @param string|int $slugOrId
212
     * @return Domain|null
213
     */
214
    public function getDomain($slugOrId): ?Domain
215
    {
216
        if (is_numeric($slugOrId)) {
217
            return Domain::find($slugOrId);
218
        } else {
219
            return Domain::where('slug', (string)$slugOrId)->first();
220
        }
221
    }
222
223
    /**
224
     * Get a module instance by name or id
225
     *
226
     * @param string|int $nameOrId
227
     * @return Module|null
228
     */
229
    public function getModule($nameOrId): ?Module
230
    {
231
        if (!$nameOrId) {
232
            return null;
233
        }
234
235
        if (is_numeric($nameOrId)) {
236
            // Use cache
237
            $modules = Cache::rememberForever('modules_by_id', function () {
238
                $modulesGroupedById = collect();
239
                Module::all()->map(function($item) use($modulesGroupedById) {
240
                    $modulesGroupedById[$item->id] = $item;
241
                    return $modulesGroupedById;
242
                });
243
                return $modulesGroupedById;
244
            });
245
            return $modules[(string) $nameOrId] ?? null;
246
        } else {
247
            // Use cache
248
            $modules = Cache::rememberForever('modules_by_name', function () {
249
                $modulesGroupedByName = collect();
250
                Module::all()->map(function($item) use($modulesGroupedByName) {
251
                    $modulesGroupedByName[$item->name] = $item;
252
                    return $modulesGroupedByName;
253
                });
254
                return $modulesGroupedByName;
255
            });
256
            return $modules[(string) $nameOrId] ?? null;
257
        }
258
    }
259
260
    /**
261
     * Get an Uitype instance by name or id
262
     *
263
     * @param string|int $nameOrId
264
     * @return Uitype|null
265
     */
266
    public function getUitype($nameOrId): ?Uitype
267
    {
268
        if (!$nameOrId) {
269
            return null;
270
        }
271
272
        if (is_numeric($nameOrId)) {
273
            // Use cache
274
            $uitypes = Cache::rememberForever('uitypes_by_id', function () {
275
                $uitypesGroupedById = collect();
276
                Uitype::all()->map(function($item) use($uitypesGroupedById) {
277
                    $uitypesGroupedById[$item->id] = $item;
278
                    return $uitypesGroupedById;
279
                });
280
                return $uitypesGroupedById;
281
            });
282
            return $uitypes[(string) $nameOrId] ?? null;
283
        } else {
284
            // Use cache
285
            $uitypes = Cache::rememberForever('uitypes_by_name', function () {
286
                $uitypesGroupedByName = collect();
287
                Uitype::all()->map(function($item) use($uitypesGroupedByName) {
288
                    $uitypesGroupedByName[$item->name] = $item;
289
                    return $uitypesGroupedByName;
290
                });
291
                return $uitypesGroupedByName;
292
            });
293
            return $uitypes[(string) $nameOrId] ?? null;
294
        }
295
    }
296
297
    /**
298
     * Get a display type instance by name or id
299
     *
300
     * @param string|int $nameOrId
301
     * @return Uitype|null
302
     */
303
    public function getDisplaytype($nameOrId): ?Displaytype
304
    {
305
        if (!$nameOrId) {
306
            return null;
307
        }
308
309
        if (is_numeric($nameOrId)) {
310
            // Use cache
311
            $displaytypes = Cache::rememberForever('displaytypes_by_id', function () {
312
                $displaytypesGroupedById = collect();
313
                Displaytype::all()->map(function($item) use($displaytypesGroupedById) {
314
                    $displaytypesGroupedById[$item->id] = $item;
315
                    return $displaytypesGroupedById;
316
                });
317
                return $displaytypesGroupedById;
318
            });
319
            return $displaytypes[(string) $nameOrId] ?? null;
320
        } else {
321
            // Use cache
322
            $displaytypes = Cache::rememberForever('displaytypes_by_name', function () {
323
                $displaytypesGroupedByName = collect();
324
                Displaytype::all()->map(function($item) use($displaytypesGroupedByName) {
325
                    $displaytypesGroupedByName[$item->name] = $item;
326
                    return $displaytypesGroupedByName;
327
                });
328
                return $displaytypesGroupedByName;
329
            });
330
            return $displaytypes[(string) $nameOrId] ?? null;
331
        }
332
    }
333
334
    /**
335
     * Get a capability instance by name or id
336
     *
337
     * @param string|int $nameOrId
338
     * @return Uitype|null
339
     */
340
    public function getCapability($nameOrId): ?Capability
341
    {
342
        if (!$nameOrId) {
343
            return null;
344
        }
345
346
        if (is_numeric($nameOrId)) {
347
            // Use cache
348
            $capabilities = Cache::rememberForever('capabilities_by_id', function () {
349
                $capabilitiesGroupedById = collect();
350
                Capability::all()->map(function($item) use($capabilitiesGroupedById) {
351
                    $capabilitiesGroupedById[$item->id] = $item;
352
                    return $capabilitiesGroupedById;
353
                });
354
                return $capabilitiesGroupedById;
355
            });
356
            return $capabilities[(string) $nameOrId] ?? null;
357
        } else {
358
            // Use cache
359
            $capabilities = Cache::rememberForever('capabilities_by_name', function () {
360
                $capabilitiesGroupedByName = collect();
361
                Capability::all()->map(function($item) use($capabilitiesGroupedByName) {
362
                    $capabilitiesGroupedByName[$item->name] = $item;
363
                    return $capabilitiesGroupedByName;
364
                });
365
                return $capabilitiesGroupedByName;
366
            });
367
            return $capabilities[(string) $nameOrId] ?? null;
368
        }
369
    }
370
371
    /**
372
     * Returns all domains without parents
373
     *
374
     * @return Collection
375
     */
376
    public function getRootDomains(): Collection
377
    {
378
        return Domain::getRoots()->get();
379
    }
380
381
    /**
382
     * Get last domain visited by the connected user, or the first one available
383
     * Priority:
384
     * 1. Last domain visited
385
     * 2. Domain where the user was created into
386
     * 3. First root domain
387
     *
388
     * @return Domain|null
389
     */
390
    public function getLastOrDefaultDomain(): ?Domain
391
    {
392
        $domain = Auth::user()->lastDomain ?? Auth::user()->domain ?? null; // On login page user is not authenticated
0 ignored issues
show
Bug introduced by
Accessing lastDomain on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
Bug introduced by
Accessing domain on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
393
394
        if (!$domain) {
395
            $domain = $this->getRootDomains()[ 0 ];
396
        }
397
398
        return $domain;
399
    }
400
401
    /**
402
     * Retrieve columns to display in a datatable table
403
     *
404
     * @param Module $module
405
     * @param integer $filterId
406
     * @param string $type
407
     * @return array
408
     */
409
    public function getDatatableColumns(Module $module, $filterId=null, $type='list'): array
410
    {
411
        $columns = [ ];
412
413
        // Get default filter
414
        if ($filterId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filterId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
415
            $filter = Filter::find($filterId);
416
        } else {
417
            $filter = Filter::where('module_id', $module->id)
418
                ->where('type', $type)
419
                ->first();
420
421
            // If there is not result, try with type = list
422
            if (empty($filter) && $type !== 'list') {
423
                $filter = Filter::where('module_id', $module->id)
424
                ->where('type', 'list')
425
                ->first();
426
            }
427
        }
428
429
        if (empty($filter)) {
430
            return [ ];
431
        }
432
433
        // Get all fields
434
        $fields = $module->fields;
435
436
        foreach ($fields as $field) {
437
            // If the field is not listable, continue
438
            if (!$field->isListable()) {
439
                continue;
440
            }
441
442
            $uitype = uitype($field->uitype_id);
443
444
            // Add the field as a new column
445
            $columns[ ] = [
446
                'name' => $field->name,
447
                'db_column' => $field->column,
448
                'uitype' => $uitype->name,
449
                'package' => $uitype->package,
450
                'data' => $field->data,
451
                'visible' => in_array($field->name, $filter->columns)
0 ignored issues
show
Bug introduced by
The property columns does not seem to exist on Uccello\Core\Models\Filter. 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...
452
            ];
453
        }
454
455
        return $columns;
456
    }
457
458
    /**
459
     * Returns a record attribute value.
460
     * It is able to follow a complex path according to models definition (e.g. 'domain.parent.name')
461
     *
462
     * @param Object $record
463
     * @param string $attribute
464
     * @return string|Object|Array|null
465
     */
466
    public function getRecordAttribute($record, string $attribute) {
467
468
        $attributeParts = explode('.', $attribute);
469
470
        if (count($attributeParts) > 0) {
471
            $value = $record;
472
473
            foreach ($attributeParts as $part) {
474
                // Get attribute value if exists
475
                if (isset($value->{$part})) {
476
                    $value = $value->{$part};
477
                }
478
                // If property does not exist return an empty value
479
                else {
480
                    $value = null;
481
                    break;
482
                }
483
            }
484
        } else {
485
            $value = $record->{$attribute};
486
        }
487
488
        return $value;
489
    }
490
491
    /**
492
     * Retrieves a record by its id or uuid
493
     *
494
     * @param int|string $idOrUuid
495
     * @param string $className
496
     * @return mixed
497
     */
498
    public function getRecordByIdOrUuid($idOrUuid, $className)
499
    {
500
        $record = null;
501
502
        if (is_numeric($idOrUuid)) {
503
            $record = $className::find($idOrUuid);
504
        } else {
505
            $record = $this->getRecordByUuid($idOrUuid);
506
        }
507
508
        return $record;
509
    }
510
511
    /**
512
     * Retrieves a record by its uuid
513
     *
514
     * @param string $uuid
515
     * @return mixed
516
     */
517
    public function getRecordByUuid($uuid)
518
    {
519
        $record = null;
520
521
        $entity = Entity::find($uuid);
522
        if ($entity) {
523
            $record = $entity->record;
524
        }
525
526
        return $record;
527
    }
528
}