• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

conedevelopment / root / 18554953619

16 Oct 2025 08:19AM UTC coverage: 75.974% (-0.3%) from 76.265%
18554953619

push

github

iamgergo
version

3355 of 4416 relevant lines covered (75.97%)

34.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.79
/src/Resources/Resource.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Cone\Root\Resources;
6

7
use Cone\Root\Actions\Action;
8
use Cone\Root\Exceptions\SaveFormDataException;
9
use Cone\Root\Fields\BelongsToMany;
10
use Cone\Root\Fields\Events;
11
use Cone\Root\Fields\Field;
12
use Cone\Root\Fields\Fields;
13
use Cone\Root\Fields\HasMany;
14
use Cone\Root\Fields\Meta;
15
use Cone\Root\Fields\MorphMany;
16
use Cone\Root\Fields\Relation;
17
use Cone\Root\Fields\Translations;
18
use Cone\Root\Filters\Filter;
19
use Cone\Root\Filters\RenderableFilter;
20
use Cone\Root\Filters\Search;
21
use Cone\Root\Filters\Sort;
22
use Cone\Root\Filters\TrashStatus;
23
use Cone\Root\Http\Middleware\Authorize;
24
use Cone\Root\Interfaces\Form;
25
use Cone\Root\Models\Translation;
26
use Cone\Root\Root;
27
use Cone\Root\Support\Alert;
28
use Cone\Root\Traits\AsForm;
29
use Cone\Root\Traits\Authorizable;
30
use Cone\Root\Traits\HasRootEvents;
31
use Cone\Root\Traits\RegistersRoutes;
32
use Cone\Root\Traits\ResolvesActions;
33
use Cone\Root\Traits\ResolvesFilters;
34
use Cone\Root\Traits\ResolvesWidgets;
35
use Cone\Root\Traits\Translatable;
36
use Cone\Root\Widgets\Metric;
37
use Cone\Root\Widgets\Widget;
38
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
39
use Illuminate\Contracts\Support\Arrayable;
40
use Illuminate\Contracts\Support\MessageBag;
41
use Illuminate\Database\Eloquent\Builder;
42
use Illuminate\Database\Eloquent\Model;
43
use Illuminate\Database\Eloquent\SoftDeletes;
44
use Illuminate\Http\Request;
45
use Illuminate\Routing\Events\RouteMatched;
46
use Illuminate\Routing\Router;
47
use Illuminate\Support\Collection;
48
use Illuminate\Support\Facades\DB;
49
use Illuminate\Support\Facades\Gate;
50
use Illuminate\Support\Facades\Redirect;
51
use Illuminate\Support\Facades\URL;
52
use Illuminate\Support\Str;
53
use Symfony\Component\HttpFoundation\Response;
54
use Throwable;
55

56
abstract class Resource implements Arrayable, Form
57
{
58
    use AsForm {
59
        AsForm::resolveFields as __resolveFields;
60
    }
61
    use Authorizable;
62
    use RegistersRoutes {
63
        RegistersRoutes::registerRoutes as __registerRoutes;
64
        RegistersRoutes::routeMatched as __routeMatched;
65
    }
66
    use ResolvesActions;
67
    use ResolvesFilters;
68
    use ResolvesWidgets;
69

70
    /**
71
     * The model class.
72
     */
73
    protected string $model;
74

75
    /**
76
     * The relations to eager load on every query.
77
     */
78
    protected array $with = [];
79

80
    /**
81
     * The relations to eager load on every query.
82
     */
83
    protected array $withCount = [];
84

85
    /**
86
     * The icon for the resource.
87
     */
88
    protected string $icon = 'archive';
89

90
    /**
91
     * The group for the resource.
92
     */
93
    protected string $group = 'General';
94

95
    /**
96
     * Boot the resource.
97
     */
98
    public function boot(Root $root): void
197✔
99
    {
100
        $root->routes(function (Router $router) use ($root): void {
197✔
101
            $this->registerRoutes($root->app['request'], $router);
197✔
102
        });
197✔
103

104
        $root->navigation->location('sidebar')->new(
197✔
105
            $this->getUri(),
197✔
106
            $this->getName(),
197✔
107
            ['icon' => $this->getIcon(), 'group' => __($this->group)],
197✔
108
        );
197✔
109
    }
110

111
    /**
112
     * Get the model for the resource.
113
     */
114
    public function getModel(): string
197✔
115
    {
116
        return $this->model;
197✔
117
    }
118

119
    /**
120
     * Get the key.
121
     */
122
    public function getKey(): string
197✔
123
    {
124
        return Str::of($this->getModel())->classBasename()->plural()->kebab()->value();
197✔
125
    }
126

127
    /**
128
     * Get the URI key.
129
     */
130
    public function getUriKey(): string
197✔
131
    {
132
        return $this->getKey();
197✔
133
    }
134

135
    /**
136
     * Get the route prefix.
137
     */
138
    public function getRoutePrefix(): string
197✔
139
    {
140
        return sprintf('resources/%s', $this->getUriKey());
197✔
141
    }
142

143
    /**
144
     * Get the route parameter name.
145
     */
146
    public function getRouteParameterName(): string
26✔
147
    {
148
        return '_resource';
26✔
149
    }
150

151
    /**
152
     * Get the name.
153
     */
154
    public function getName(): string
197✔
155
    {
156
        return __(Str::of($this->getModel())->classBasename()->headline()->plural()->value());
197✔
157
    }
158

159
    /**
160
     * Get the model name.
161
     */
162
    public function getModelName(): string
5✔
163
    {
164
        return __(Str::of($this->getModel())->classBasename()->value());
5✔
165
    }
166

167
    /**
168
     * Get the model instance.
169
     */
170
    public function getModelInstance(): Model
27✔
171
    {
172
        return new ($this->getModel());
27✔
173
    }
174

175
    /**
176
     * Set the resource icon.
177
     */
178
    public function icon(string $icon): static
1✔
179
    {
180
        $this->icon = $icon;
1✔
181

182
        return $this;
1✔
183
    }
184

185
    /**
186
     * Get the resource icon.
187
     */
188
    public function getIcon(): string
197✔
189
    {
190
        return $this->icon;
197✔
191
    }
192

193
    /**
194
     * Get the policy for the model.
195
     */
196
    public function getPolicy(): mixed
25✔
197
    {
198
        return Gate::getPolicyFor($this->getModel());
25✔
199
    }
200

201
    /**
202
     * Resolve the ability.
203
     */
204
    public function resolveAbility(string $ability, Request $request, Model $model, ...$arguments): bool
4✔
205
    {
206
        $policy = $this->getPolicy();
4✔
207

208
        return is_null($policy)
4✔
209
            || ! method_exists($policy, $ability)
4✔
210
            || Gate::allows($ability, [$model, ...$arguments]);
4✔
211
    }
212

213
    /**
214
     * Map the resource abilities.
215
     */
216
    public function mapResourceAbilities(Request $request): array
4✔
217
    {
218
        return [
4✔
219
            'viewAny' => $this->resolveAbility('viewAny', $request, $this->getModelInstance()),
4✔
220
            'create' => $this->resolveAbility('create', $request, $this->getModelInstance()),
4✔
221
        ];
4✔
222
    }
223

224
    /**
225
     * Map the model abilities.
226
     */
227
    public function mapModelAbilities(Request $request, Model $model): array
3✔
228
    {
229
        return [
3✔
230
            'view' => $this->resolveAbility('view', $request, $model),
3✔
231
            'update' => $this->resolveAbility('update', $request, $model),
3✔
232
            'restore' => $this->resolveAbility('restore', $request, $model),
3✔
233
            'delete' => $this->resolveAbility('delete', $request, $model),
3✔
234
            'forceDelete' => $this->resolveAbility('forceDelete', $request, $model),
3✔
235
        ];
3✔
236
    }
237

238
    /**
239
     * Set the relations to eagerload.
240
     */
241
    public function with(array $relations): static
1✔
242
    {
243
        $this->with = $relations;
1✔
244

245
        return $this;
1✔
246
    }
247

248
    /**
249
     * Set the relation counts to eagerload.
250
     */
251
    public function withCount(array $relations): static
×
252
    {
253
        $this->withCount = $relations;
×
254

255
        return $this;
×
256
    }
257

258
    /**
259
     * Make a new Eloquent query instance.
260
     */
261
    public function query(): Builder
24✔
262
    {
263
        return $this->getModelInstance()->newQuery()->with($this->with)->withCount($this->withCount);
24✔
264
    }
265

266
    /**
267
     * Resolve the query for the given request.
268
     */
269
    public function resolveQuery(Request $request): Builder
24✔
270
    {
271
        return $this->query();
24✔
272
    }
273

274
    /**
275
     * Resolve the filtered query for the given request.
276
     */
277
    public function resolveFilteredQuery(Request $request): Builder
3✔
278
    {
279
        return $this->resolveFilters($request)->apply($request, $this->resolveQuery($request));
3✔
280
    }
281

282
    /**
283
     * Resolve the route binding query.
284
     */
285
    public function resolveRouteBindingQuery(Request $request): Builder
20✔
286
    {
287
        return $this->resolveQuery($request)->when(
20✔
288
            $this->isSoftDeletable(),
20✔
289
            static fn (Builder $query): Builder => $query->withTrashed()
20✔
290
        );
20✔
291
    }
292

293
    /**
294
     * Resolve the resource model for a bound value.
295
     */
296
    public function resolveRouteBinding(Request $request, string $id): Model
20✔
297
    {
298
        return $this->resolveRouteBindingQuery($request)->findOrFail($id);
20✔
299
    }
300

301
    /**
302
     * Determine if the model soft deletable.
303
     */
304
    public function isSoftDeletable(): bool
24✔
305
    {
306
        return in_array(SoftDeletes::class, class_uses_recursive($this->getModel()));
24✔
307
    }
308

309
    /**
310
     * Get the URL for the given model.
311
     */
312
    public function modelUrl(Model $model): string
6✔
313
    {
314
        return sprintf('%s/%s', $this->getUri(), $model->exists ? $model->getKey() : '');
6✔
315
    }
316

317
    /**
318
     * Get the title for the model.
319
     */
320
    public function modelTitle(Model $model): string
7✔
321
    {
322
        return (string) $model->getKey();
7✔
323
    }
324

325
    /**
326
     * Determine whether the resource model has root events.
327
     */
328
    public function hasRootEvents(): bool
197✔
329
    {
330
        return in_array(HasRootEvents::class, class_uses_recursive($this->getModel()));
197✔
331
    }
332

333
    /**
334
     * Resolve the events field.
335
     */
336
    public function resolveEventsField(Request $request): ?Events
197✔
337
    {
338
        return $this->hasRootEvents() ? new Events : null;
197✔
339
    }
340

341
    /**
342
     * Determine whether the resource model has root events.
343
     */
344
    public function translatable(): bool
197✔
345
    {
346
        return in_array(Translatable::class, class_uses_recursive($this->getModel()));
197✔
347
    }
348

349
    /**
350
     * Resolve the translations field.
351
     */
352
    public function resolveTranslationsField(Request $request): ?Translations
197✔
353
    {
354
        if (! $this->translatable()) {
197✔
355
            return null;
×
356
        }
357

358
        return Translations::make()
197✔
359
            ->withFields(function () use ($request): array {
197✔
360
                return $this->resolveFields($request)
197✔
361
                    ->translatable()
197✔
362
                    ->map(static function (Field $field): Field {
197✔
363
                        return (clone $field)
×
364
                            ->translatable(false)
×
365
                            ->value(static function (Request $request, Translation $model) use ($field): mixed {
×
366
                                return $model->values[$field->getModelAttribute()] ?? null;
×
367
                            })
×
368
                            ->hydrate(static function (Request $request, Translation $model, mixed $value) use ($field): void {
×
369
                                $model->values[$field->getModelAttribute()] = $value;
×
370
                            });
×
371
                    })->all();
197✔
372
            });
197✔
373
    }
374

375
    /**
376
     * Resolve the fields collection.
377
     */
378
    public function resolveFields(Request $request): Fields
197✔
379
    {
380
        if (is_null($this->fields)) {
197✔
381
            $this->withFields(fn (): array => array_values(array_filter([
197✔
382
                $this->resolveTranslationsField($request),
197✔
383
                $this->resolveEventsField($request),
197✔
384
            ])));
197✔
385
        }
386

387
        return $this->__resolveFields($request);
197✔
388
    }
389

390
    /**
391
     * Define the filters for the object.
392
     */
393
    public function filters(Request $request): array
4✔
394
    {
395
        $fields = $this->resolveFields($request)->authorized($request);
4✔
396

397
        $searchables = $fields->searchable();
4✔
398

399
        $sortables = $fields->sortable();
4✔
400

401
        $filterables = $fields->filterable();
4✔
402

403
        return array_values(array_filter([
4✔
404
            $searchables->isNotEmpty() ? new Search($searchables) : null,
4✔
405
            $sortables->isNotEmpty() ? new Sort($sortables) : null,
4✔
406
            $this->isSoftDeletable() ? new TrashStatus : null,
4✔
407
            ...$filterables->map->toFilter()->all(),
4✔
408
        ]));
4✔
409
    }
410

411
    /**
412
     * Handle the callback for the field resolution.
413
     */
414
    protected function resolveField(Request $request, Field $field): void
197✔
415
    {
416
        $field->setAttribute('form', $this->getKey());
197✔
417
        $field->resolveErrorsUsing(fn (Request $request): MessageBag => $this->errors($request));
197✔
418

419
        if ($field instanceof Relation) {
197✔
420
            $field->resolveRouteKeyNameUsing(fn (): string => Str::of($field->getRelationName())->singular()->ucfirst()->prepend($this->getKey())->value());
197✔
421
        }
422
    }
423

424
    /**
425
     * Handle the callback for the filter resolution.
426
     */
427
    protected function resolveFilter(Request $request, Filter $filter): void
4✔
428
    {
429
        $filter->setKey(sprintf('%s_%s', $this->getKey(), $filter->getKey()));
4✔
430
    }
431

432
    /**
433
     * Handle the callback for the action resolution.
434
     */
435
    protected function resolveAction(Request $request, Action $action): void
197✔
436
    {
437
        $action->withQuery(fn (): Builder => $this->resolveFilteredQuery($request));
197✔
438
    }
439

440
    /**
441
     * Handle the callback for the widget resolution.
442
     */
443
    protected function resolveWidget(Request $request, Widget $widget): void
197✔
444
    {
445
        if ($widget instanceof Metric) {
197✔
446
            $widget->withQuery(fn (): Builder => $this->resolveQuery($request));
197✔
447
        }
448
    }
449

450
    /**
451
     * Get the per page options.
452
     */
453
    public function getPerPageOptions(): array
1✔
454
    {
455
        return Collection::make([$this->getModelInstance()->getPerPage()])
1✔
456
            ->merge([15, 25, 50, 100])
1✔
457
            ->filter()
1✔
458
            ->unique()
1✔
459
            ->values()
1✔
460
            ->toArray();
1✔
461
    }
462

463
    /**
464
     * Get the per page key.
465
     */
466
    public function getPerPageKey(): string
1✔
467
    {
468
        return sprintf('%s_per_page', $this->getKey());
1✔
469
    }
470

471
    /**
472
     * Get the sort key.
473
     */
474
    public function getSortKey(): string
1✔
475
    {
476
        return sprintf('%s_sort', $this->getKey());
1✔
477
    }
478

479
    /**
480
     * Perform the query and the pagination.
481
     */
482
    public function paginate(Request $request): LengthAwarePaginator
1✔
483
    {
484
        return $this->resolveFilteredQuery($request)
1✔
485
            ->tap(function (Builder $query) use ($request): void {
1✔
486
                $this->resolveFields($request)
1✔
487
                    ->authorized($request, $query->getModel())
1✔
488
                    ->visible('index')
1✔
489
                    ->filter(fn (Field $field): bool => $field instanceof Relation)
1✔
490
                    ->each(static function (Relation $relation) use ($query, $request): void {
1✔
491
                        if ($relation instanceof BelongsToMany || $relation instanceof HasMany || $relation instanceof MorphMany) {
1✔
492
                            $relation->resolveAggregate($request, $query);
1✔
493
                        } elseif ($relation instanceof Meta) {
1✔
494
                            $query->with('metaData');
×
495
                        } else {
496
                            $query->with($relation->getRelationName());
1✔
497
                        }
498
                    });
1✔
499
            })
1✔
500
            ->latest()
1✔
501
            ->paginate($request->input($this->getPerPageKey()))
1✔
502
            ->withQueryString()
1✔
503
            ->through(fn (Model $model): array => $this->mapModel($request, $model));
1✔
504
    }
505

506
    /**
507
     * Map the model.
508
     */
509
    public function mapModel(Request $request, Model $model): array
1✔
510
    {
511
        return [
1✔
512
            'id' => $model->getKey(),
1✔
513
            'url' => $this->modelUrl($model),
1✔
514
            'model' => $model,
1✔
515
            'abilities' => $this->mapModelAbilities($request, $model),
1✔
516
            'fields' => $this->resolveFields($request)
1✔
517
                ->authorized($request, $model)
1✔
518
                ->visible('index')
1✔
519
                ->mapToDisplay($request, $model),
1✔
520
        ];
1✔
521
    }
522

523
    /**
524
     * Handle the request.
525
     */
526
    public function handleFormRequest(Request $request, Model $model): Response
3✔
527
    {
528
        $this->validateFormRequest($request, $model);
3✔
529

530
        try {
531
            return DB::transaction(function () use ($request, $model): Response {
3✔
532
                $this->resolveFields($request)
3✔
533
                    ->authorized($request, $model)
3✔
534
                    ->visible($request->isMethod('POST') ? 'create' : 'update')
3✔
535
                    ->subResource(false)
3✔
536
                    ->persist($request, $model);
3✔
537

538
                $this->saving($request, $model);
3✔
539

540
                $model->save();
3✔
541

542
                if (in_array(HasRootEvents::class, class_uses_recursive($model))) {
3✔
543
                    $model->recordRootEvent(
3✔
544
                        $model->wasRecentlyCreated ? 'Created' : 'Updated',
3✔
545
                        $request->user()
3✔
546
                    );
3✔
547
                }
548

549
                $this->saved($request, $model);
3✔
550

551
                return $this->formResponse($request, $model);
3✔
552
            });
3✔
553
        } catch (Throwable $exception) {
×
554
            report($exception);
×
555

556
            throw new SaveFormDataException($exception->getMessage());
×
557
        }
558
    }
559

560
    /**
561
     * Make a form response.
562
     */
563
    public function formResponse(Request $request, Model $model): Response
3✔
564
    {
565
        return Redirect::to($this->modelUrl($model))
3✔
566
            ->with('alerts.resource-saved', Alert::success(__('The resource has been saved!')));
3✔
567
    }
568

569
    /**
570
     * Handle the saving form event.
571
     */
572
    public function saving(Request $request, Model $model): void
3✔
573
    {
574
        //
575
    }
3✔
576

577
    /**
578
     * Handle the saved form event.
579
     */
580
    public function saved(Request $request, Model $model): void
3✔
581
    {
582
        //
583
    }
3✔
584

585
    /**
586
     * Register the routes.
587
     */
588
    public function registerRoutes(Request $request, Router $router): void
197✔
589
    {
590
        $this->__registerRoutes($request, $router);
197✔
591

592
        $router->group([
197✔
593
            'prefix' => $this->getRoutePrefix(),
197✔
594
            'middleware' => $this->getRouteMiddleware(),
197✔
595
        ], function (Router $router) use ($request): void {
197✔
596
            $this->resolveActions($request)->registerRoutes($request, $router);
197✔
597
            $this->resolveWidgets($request)->registerRoutes($request, $router);
197✔
598

599
            $router->prefix('{resourceModel}')->group(function (Router $router) use ($request): void {
197✔
600
                $this->resolveFields($request)->registerRoutes($request, $router);
197✔
601
            });
197✔
602
        });
197✔
603
    }
604

605
    /**
606
     * Get the route middleware for the registered routes.
607
     */
608
    public function getRouteMiddleware(): array
197✔
609
    {
610
        return [
197✔
611
            Authorize::class.':_resource',
197✔
612
        ];
197✔
613
    }
614

615
    /**
616
     * Handle the route matched event.
617
     */
618
    public function routeMatched(RouteMatched $event): void
25✔
619
    {
620
        $event->route->defaults('resource', $this->getKey());
25✔
621

622
        if ($controller = $event->route->getController()) {
25✔
623
            $controller->middleware($this->getRouteMiddleware());
25✔
624

625
            if (! is_null($this->getPolicy())) {
25✔
626
                $controller->authorizeResource($this->getModel(), 'resourceModel');
×
627
            }
628
        }
629

630
        $this->__routeMatched($event);
25✔
631
    }
632

633
    /**
634
     * Get the instance as an array.
635
     */
636
    public function toArray(): array
4✔
637
    {
638
        return [
4✔
639
            'icon' => $this->getIcon(),
4✔
640
            'key' => $this->getKey(),
4✔
641
            'model' => $this->getModel(),
4✔
642
            'modelName' => $this->getModelName(),
4✔
643
            'name' => $this->getName(),
4✔
644
            'uriKey' => $this->getUriKey(),
4✔
645
            'url' => $this->getUri(),
4✔
646
            'baseUrl' => $this->getUri(),
4✔
647
        ];
4✔
648
    }
649

650
    /**
651
     * Get the index representation of the resource.
652
     */
653
    public function toIndex(Request $request): array
1✔
654
    {
655
        return array_merge($this->toArray(), [
1✔
656
            'template' => 'root::resources.index',
1✔
657
            'title' => $this->getName(),
1✔
658
            'standaloneActions' => $this->resolveActions($request)
1✔
659
                ->authorized($request, $model = $this->getModelInstance())
1✔
660
                ->standalone()
1✔
661
                ->mapToForms($request, $model),
1✔
662
            'actions' => $this->resolveActions($request)
1✔
663
                ->authorized($request, $model = $this->getModelInstance())
1✔
664
                ->visible('index')
1✔
665
                ->standalone(false)
1✔
666
                ->mapToForms($request, $model),
1✔
667
            'data' => $this->paginate($request),
1✔
668
            'widgets' => $this->resolveWidgets($request)
1✔
669
                ->authorized($request)
1✔
670
                ->visible('index')
1✔
671
                ->mapToDisplay($request),
1✔
672
            'perPageOptions' => $this->getPerPageOptions(),
1✔
673
            'perPageKey' => $this->getPerPageKey(),
1✔
674
            'sortKey' => $this->getSortKey(),
1✔
675
            'filters' => $this->resolveFilters($request)
1✔
676
                ->authorized($request)
1✔
677
                ->renderable()
1✔
678
                ->map(static fn (RenderableFilter $filter): array => $filter->toField()->toInput($request, $model))
1✔
679
                ->all(),
1✔
680
            'activeFilters' => $this->resolveFilters($request)->active($request)->count(),
1✔
681
            'url' => $this->getUri(),
1✔
682
            'abilities' => $this->mapResourceAbilities($request),
1✔
683
        ]);
1✔
684
    }
685

686
    /**
687
     * Get the create representation of the resource.
688
     */
689
    public function toCreate(Request $request): array
1✔
690
    {
691
        return array_merge($this->toArray(), [
1✔
692
            'template' => 'root::resources.form',
1✔
693
            'title' => __('Create :resource', ['resource' => $this->getModelName()]),
1✔
694
            'model' => $model = $this->getModelInstance(),
1✔
695
            'action' => $this->getUri(),
1✔
696
            'method' => 'POST',
1✔
697
            'uploads' => $this->hasFileField($request),
1✔
698
            'fields' => $this->resolveFields($request)
1✔
699
                ->subResource(false)
1✔
700
                ->authorized($request, $model)
1✔
701
                ->visible('create')
1✔
702
                ->mapToInputs($request, $model),
1✔
703
            'abilities' => $this->mapResourceAbilities($request),
1✔
704
        ]);
1✔
705
    }
706

707
    /**
708
     * Get the edit representation of the resource.
709
     */
710
    public function toShow(Request $request, Model $model): array
1✔
711
    {
712
        return array_merge($this->toArray(), [
1✔
713
            'template' => 'root::resources.show',
1✔
714
            'title' => sprintf('%s: %s', $this->getModelName(), $this->modelTitle($model)),
1✔
715
            'model' => $model,
1✔
716
            'action' => $this->modelUrl($model),
1✔
717
            'fields' => $this->resolveFields($request)
1✔
718
                ->subResource(false)
1✔
719
                ->authorized($request, $model)
1✔
720
                ->visible('show')
1✔
721
                ->mapToDisplay($request, $model),
1✔
722
            'actions' => $this->resolveActions($request)
1✔
723
                ->authorized($request, $model)
1✔
724
                ->visible('show')
1✔
725
                ->standalone(false)
1✔
726
                ->mapToForms($request, $model),
1✔
727
            'widgets' => $this->resolveWidgets($request)
1✔
728
                ->authorized($request, $model)
1✔
729
                ->visible('show')
1✔
730
                ->mapToDisplay($request),
1✔
731
            'relations' => $this->resolveFields($request)
1✔
732
                ->subResource()
1✔
733
                ->authorized($request, $model)
1✔
734
                ->map(static fn (Relation $relation): array => array_merge($relation->toSubResource($request, $model), [
1✔
735
                    'url' => URL::query($relation->modelUrl($model), $relation->parseQueryString($request->fullUrl())),
1✔
736
                ])),
1✔
737
            'abilities' => array_merge(
1✔
738
                $this->mapResourceAbilities($request),
1✔
739
                $this->mapModelAbilities($request, $model)
1✔
740
            ),
1✔
741
        ]);
1✔
742
    }
743

744
    /**
745
     * Get the edit representation of the resource.
746
     */
747
    public function toEdit(Request $request, Model $model): array
1✔
748
    {
749
        return array_merge($this->toArray(), [
1✔
750
            'template' => 'root::resources.form',
1✔
751
            'title' => __('Edit :resource: :model', ['resource' => $this->getModelName(), 'model' => $this->modelTitle($model)]),
1✔
752
            'model' => $model,
1✔
753
            'action' => $this->modelUrl($model),
1✔
754
            'method' => 'PATCH',
1✔
755
            'uploads' => $this->hasFileField($request),
1✔
756
            'fields' => $this->resolveFields($request)
1✔
757
                ->subResource(false)
1✔
758
                ->authorized($request, $model)
1✔
759
                ->visible('update')
1✔
760
                ->mapToInputs($request, $model),
1✔
761
            'abilities' => array_merge(
1✔
762
                $this->mapResourceAbilities($request),
1✔
763
                $this->mapModelAbilities($request, $model)
1✔
764
            ),
1✔
765
        ]);
1✔
766
    }
767
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc