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

conedevelopment / root / 12401990425

18 Dec 2024 09:56PM UTC coverage: 77.882% (+0.07%) from 77.817%
12401990425

push

github

iamgergo
fix

1 of 1 new or added line in 1 file covered. (100.0%)

56 existing lines in 3 files now uncovered.

2662 of 3418 relevant lines covered (77.88%)

34.04 hits per line

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

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

3
namespace Cone\Root\Resources;
4

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

50
abstract class Resource implements Arrayable, Form
51
{
52
    use AsForm {
53
        AsForm::resolveFields as __resolveFields;
54
    }
55
    use Authorizable;
56
    use RegistersRoutes {
57
        RegistersRoutes::registerRoutes as __registerRoutes;
58
        RegistersRoutes::routeMatched as __routeMatched;
59
    }
60
    use ResolvesActions;
61
    use ResolvesFilters;
62
    use ResolvesWidgets;
63

64
    /**
65
     * The model class.
66
     */
67
    protected string $model;
68

69
    /**
70
     * The relations to eager load on every query.
71
     */
72
    protected array $with = [];
73

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

79
    /**
80
     * The icon for the resource.
81
     */
82
    protected string $icon = 'archive';
83

84
    /**
85
     * The group for the resource.
86
     */
87
    protected string $group = 'General';
88

89
    /**
90
     * Boot the resource.
91
     */
92
    public function boot(Root $root): void
93
    {
94
        $root->routes(function (Router $router) use ($root): void {
198✔
95
            $this->registerRoutes($root->app['request'], $router);
198✔
96
        });
198✔
97

98
        $root->navigation->location('sidebar')->new(
198✔
99
            $this->getUri(),
198✔
100
            $this->getName(),
198✔
101
            ['icon' => $this->getIcon(), 'group' => __($this->group)],
198✔
102
        );
198✔
103
    }
104

105
    /**
106
     * Get the model for the resource.
107
     */
108
    public function getModel(): string
109
    {
110
        return $this->model;
198✔
111
    }
112

113
    /**
114
     * Get the key.
115
     */
116
    public function getKey(): string
117
    {
118
        return Str::of($this->getModel())->classBasename()->plural()->kebab()->value();
198✔
119
    }
120

121
    /**
122
     * Get the URI key.
123
     */
124
    public function getUriKey(): string
125
    {
126
        return $this->getKey();
198✔
127
    }
128

129
    /**
130
     * Get the route parameter name.
131
     */
132
    public function getRouteParameterName(): string
133
    {
134
        return '_resource';
26✔
135
    }
136

137
    /**
138
     * Get the name.
139
     */
140
    public function getName(): string
141
    {
142
        return __(Str::of($this->getModel())->classBasename()->headline()->plural()->value());
198✔
143
    }
144

145
    /**
146
     * Get the model name.
147
     */
148
    public function getModelName(): string
149
    {
150
        return __(Str::of($this->getModel())->classBasename()->value());
5✔
151
    }
152

153
    /**
154
     * Get the model instance.
155
     */
156
    public function getModelInstance(): Model
157
    {
158
        return new ($this->getModel());
27✔
159
    }
160

161
    /**
162
     * Set the resource icon.
163
     */
164
    public function icon(string $icon): static
165
    {
166
        $this->icon = $icon;
1✔
167

168
        return $this;
1✔
169
    }
170

171
    /**
172
     * Get the resource icon.
173
     */
174
    public function getIcon(): string
175
    {
176
        return $this->icon;
198✔
177
    }
178

179
    /**
180
     * Get the policy for the model.
181
     */
182
    public function getPolicy(): mixed
183
    {
184
        return Gate::getPolicyFor($this->getModel());
25✔
185
    }
186

187
    /**
188
     * Resolve the ability.
189
     */
190
    public function resolveAbility(string $ability, Request $request, Model $model, ...$arguments): bool
191
    {
192
        $policy = $this->getPolicy();
5✔
193

194
        return is_null($policy)
5✔
195
            || ! method_exists($policy, $ability)
5✔
196
            || Gate::allows($ability, [$model, ...$arguments]);
5✔
197
    }
198

199
    /**
200
     * Map the resource abilities.
201
     */
202
    public function mapResourceAbilities(Request $request): array
203
    {
204
        return [
4✔
205
            'viewAny' => $this->resolveAbility('viewAny', $request, $this->getModelInstance()),
4✔
206
            'create' => $this->resolveAbility('create', $request, $this->getModelInstance()),
4✔
207
        ];
4✔
208
    }
209

210
    /**
211
     * Map the model abilities.
212
     */
213
    public function mapModelAbilities(Request $request, Model $model): array
214
    {
215
        return [
3✔
216
            'view' => $this->resolveAbility('view', $request, $model),
3✔
217
            'update' => $this->resolveAbility('update', $request, $model),
3✔
218
            'restore' => $this->resolveAbility('restore', $request, $model),
3✔
219
            'delete' => $this->resolveAbility('delete', $request, $model),
3✔
220
            'forceDelete' => $this->resolveAbility('forceDelete', $request, $model),
3✔
221
        ];
3✔
222
    }
223

224
    /**
225
     * Set the relations to eagerload.
226
     */
227
    public function with(array $relations): static
228
    {
229
        $this->with = $relations;
1✔
230

231
        return $this;
1✔
232
    }
233

234
    /**
235
     * Set the relation counts to eagerload.
236
     */
237
    public function withCount(array $relations): static
238
    {
239
        $this->withCount = $relations;
×
240

UNCOV
241
        return $this;
×
242
    }
243

244
    /**
245
     * Make a new Eloquent query instance.
246
     */
247
    public function query(): Builder
248
    {
249
        return $this->getModelInstance()->newQuery()->with($this->with)->withCount($this->withCount);
24✔
250
    }
251

252
    /**
253
     * Resolve the query for the given request.
254
     */
255
    public function resolveQuery(Request $request): Builder
256
    {
257
        return $this->query();
24✔
258
    }
259

260
    /**
261
     * Resolve the filtered query for the given request.
262
     */
263
    public function resolveFilteredQuery(Request $request): Builder
264
    {
265
        return $this->resolveFilters($request)->apply($request, $this->resolveQuery($request));
3✔
266
    }
267

268
    /**
269
     * Resolve the route binding query.
270
     */
271
    public function resolveRouteBindingQuery(Request $request): Builder
272
    {
273
        return $this->resolveQuery($request)
20✔
274
            ->withoutEagerLoads()
20✔
275
            ->when(
20✔
276
                $this->isSoftDeletable(),
20✔
277
                static function (Builder $query): Builder {
20✔
278
                    return $query->withTrashed();
20✔
279
                }
20✔
280
            );
20✔
281
    }
282

283
    /**
284
     * Resolve the resource model for a bound value.
285
     */
286
    public function resolveRouteBinding(Request $request, string $id): Model
287
    {
288
        return $this->resolveRouteBindingQuery($request)->findOrFail($id);
20✔
289
    }
290

291
    /**
292
     * Determine if the model soft deletable.
293
     */
294
    public function isSoftDeletable(): bool
295
    {
296
        return in_array(SoftDeletes::class, class_uses_recursive($this->getModel()));
24✔
297
    }
298

299
    /**
300
     * Get the URL for the given model.
301
     */
302
    public function modelUrl(Model $model): string
303
    {
304
        return sprintf('%s/%s', $this->getUri(), $model->exists ? $model->getKey() : '');
6✔
305
    }
306

307
    /**
308
     * Get the title for the model.
309
     */
310
    public function modelTitle(Model $model): string
311
    {
312
        return $model->getKey();
7✔
313
    }
314

315
    /**
316
     * Determine whether the resource model has root events.
317
     */
318
    public function hasRootEvents(): bool
319
    {
320
        return in_array(HasRootEvents::class, class_uses_recursive($this->getModel()));
198✔
321
    }
322

323
    /**
324
     * Resolve the events field.
325
     */
326
    public function resolveEventsField(Request $request): ?Events
327
    {
328
        return $this->hasRootEvents() ? new Events : null;
198✔
329
    }
330

331
    /**
332
     * Determine whether the resource model has root events.
333
     */
334
    public function translatable(): bool
335
    {
336
        return in_array(Translatable::class, class_uses_recursive($this->getModel()));
198✔
337
    }
338

339
    /**
340
     * Resolve the translations field.
341
     */
342
    public function resolveTranslationsField(Request $request): ?Translations
343
    {
344
        return $this->translatable()
198✔
345
            ? Translations::make()
198✔
346
                ->withFields(function () use ($request): array {
198✔
347
                    return $this->resolveFields($request)
198✔
348
                        ->translatable()
198✔
349
                        ->map(static function (Field $field): Field {
198✔
350
                            return (clone $field)
×
351
                                ->translatable(false)
×
352
                                ->setModelAttribute($key = 'values->'.$field->getModelAttribute())
×
UNCOV
353
                                ->name($key)
×
UNCOV
354
                                ->id($key);
×
355
                        })
198✔
356
                        ->all();
198✔
357
                })
198✔
358
            : null;
198✔
359
    }
360

361
    /**
362
     * Resolve the fields collection.
363
     */
364
    public function resolveFields(Request $request): Fields
365
    {
366
        if (is_null($this->fields)) {
198✔
367
            $this->withFields(function () use ($request): array {
198✔
368
                return array_values(array_filter([
198✔
369
                    $this->resolveTranslationsField($request),
198✔
370
                    $this->resolveEventsField($request),
198✔
371
                ]));
198✔
372
            });
198✔
373
        }
374

375
        return $this->__resolveFields($request);
198✔
376
    }
377

378
    /**
379
     * Define the filters for the object.
380
     */
381
    public function filters(Request $request): array
382
    {
383
        $fields = $this->resolveFields($request)->authorized($request);
4✔
384

385
        $searchables = $fields->searchable();
4✔
386

387
        $sortables = $fields->sortable();
4✔
388

389
        return array_values(array_filter([
4✔
390
            $searchables->isNotEmpty() ? new Search($searchables) : null,
4✔
391
            $sortables->isNotEmpty() ? new Sort($sortables) : null,
4✔
392
            $this->isSoftDeletable() ? new TrashStatus : null,
4✔
393
        ]));
4✔
394
    }
395

396
    /**
397
     * Handle the callback for the field resolution.
398
     */
399
    protected function resolveField(Request $request, Field $field): void
400
    {
401
        $field->setAttribute('form', $this->getKey());
198✔
402
        $field->resolveErrorsUsing(fn (Request $request): MessageBag => $this->errors($request));
198✔
403

404
        if ($field instanceof Relation) {
198✔
405
            $field->resolveRouteKeyNameUsing(function () use ($field): string {
198✔
406
                return Str::of($field->getRelationName())->singular()->ucfirst()->prepend($this->getKey())->value();
198✔
407
            });
198✔
408
        }
409
    }
410

411
    /**
412
     * Handle the callback for the filter resolution.
413
     */
414
    protected function resolveFilter(Request $request, Filter $filter): void
415
    {
416
        $filter->setKey(sprintf('%s_%s', $this->getKey(), $filter->getKey()));
4✔
417
    }
418

419
    /**
420
     * Handle the callback for the action resolution.
421
     */
422
    protected function resolveAction(Request $request, Action $action): void
423
    {
424
        $action->withQuery(fn (): Builder => $this->resolveFilteredQuery($request));
198✔
425
    }
426

427
    /**
428
     * Handle the callback for the widget resolution.
429
     */
430
    protected function resolveWidget(Request $request, Widget $widget): void
431
    {
432
        if ($widget instanceof Metric) {
198✔
433
            $widget->withQuery(fn (): Builder => $this->resolveQuery($request));
198✔
434
        }
435
    }
436

437
    /**
438
     * Get the per page options.
439
     */
440
    public function getPerPageOptions(): array
441
    {
442
        return Collection::make([$this->getModelInstance()->getPerPage()])
1✔
443
            ->merge([15, 25, 50, 100])
1✔
444
            ->filter()
1✔
445
            ->unique()
1✔
446
            ->values()
1✔
447
            ->toArray();
1✔
448
    }
449

450
    /**
451
     * Get the per page key.
452
     */
453
    public function getPerPageKey(): string
454
    {
455
        return sprintf('%s_per_page', $this->getKey());
1✔
456
    }
457

458
    /**
459
     * Get the sort key.
460
     */
461
    public function getSortKey(): string
462
    {
463
        return sprintf('%s_sort', $this->getKey());
1✔
464
    }
465

466
    /**
467
     * Perform the query and the pagination.
468
     */
469
    public function paginate(Request $request): LengthAwarePaginator
470
    {
471
        return $this->resolveFilteredQuery($request)
1✔
472
            ->tap(function (Builder $query) use ($request): void {
1✔
473
                $this->resolveFields($request)
1✔
474
                    ->authorized($request, $query->getModel())
1✔
475
                    ->visible('index')
1✔
476
                    ->filter(fn (Field $field): bool => $field instanceof Relation)
1✔
477
                    ->each(static function (Relation $relation) use ($query, $request): void {
1✔
478
                        if ($relation instanceof BelongsToMany || $relation instanceof HasMany || $relation instanceof MorphMany) {
1✔
479
                            $relation->resolveAggregate($request, $query);
1✔
480
                        } elseif ($relation instanceof Meta) {
1✔
UNCOV
481
                            $query->with('metaData');
×
482
                        } else {
483
                            $query->with($relation->getRelationName());
1✔
484
                        }
485
                    });
1✔
486
            })
1✔
487
            ->latest()
1✔
488
            ->paginate($request->input($this->getPerPageKey()))
1✔
489
            ->withQueryString()
1✔
490
            ->through(function (Model $model) use ($request): array {
1✔
491
                return $this->mapModel($request, $model);
1✔
492
            });
1✔
493
    }
494

495
    /**
496
     * Map the model.
497
     */
498
    public function mapModel(Request $request, Model $model): array
499
    {
500
        return [
1✔
501
            'id' => $model->getKey(),
1✔
502
            'url' => $this->modelUrl($model),
1✔
503
            'model' => $model,
1✔
504
            'abilities' => $this->mapModelAbilities($request, $model),
1✔
505
            'fields' => $this->resolveFields($request)
1✔
506
                ->authorized($request, $model)
1✔
507
                ->visible('index')
1✔
508
                ->mapToDisplay($request, $model),
1✔
509
        ];
1✔
510
    }
511

512
    /**
513
     * Handle the request.
514
     */
515
    public function handleFormRequest(Request $request, Model $model): void
516
    {
517
        $this->validateFormRequest($request, $model);
3✔
518

519
        try {
520
            DB::beginTransaction();
3✔
521

522
            $this->resolveFields($request)
3✔
523
                ->authorized($request, $model)
3✔
524
                ->visible($request->isMethod('POST') ? 'create' : 'update')
3✔
525
                ->subResource(false)
3✔
526
                ->persist($request, $model);
3✔
527

528
            $this->saving($request, $model);
3✔
529

530
            $model->save();
3✔
531

532
            if (in_array(HasRootEvents::class, class_uses_recursive($model))) {
3✔
533
                $model->recordRootEvent(
3✔
534
                    $model->wasRecentlyCreated ? 'Created' : 'Updated',
3✔
535
                    $request->user()
3✔
536
                );
3✔
537
            }
538

539
            $this->saved($request, $model);
3✔
540

541
            DB::commit();
3✔
UNCOV
542
        } catch (Throwable $exception) {
×
UNCOV
543
            report($exception);
×
544

UNCOV
545
            DB::rollBack();
×
546

UNCOV
547
            throw new SaveFormDataException($exception->getMessage());
×
548
        }
549
    }
550

551
    /**
552
     * Handle the saving form event.
553
     */
554
    public function saving(Request $request, Model $model): void
555
    {
556
        //
557
    }
3✔
558

559
    /**
560
     * Handle the saved form event.
561
     */
562
    public function saved(Request $request, Model $model): void
563
    {
564
        //
565
    }
3✔
566

567
    /**
568
     * Register the routes.
569
     */
570
    public function registerRoutes(Request $request, Router $router): void
571
    {
572
        $this->__registerRoutes($request, $router);
198✔
573

574
        $router->group([
198✔
575
            'prefix' => $this->getUriKey(),
198✔
576
            'middleware' => $this->getRouteMiddleware(),
198✔
577
        ], function (Router $router) use ($request): void {
198✔
578
            $this->resolveActions($request)->registerRoutes($request, $router);
198✔
579
            $this->resolveWidgets($request)->registerRoutes($request, $router);
198✔
580

581
            $router->prefix('{resourceModel}')->group(function (Router $router) use ($request): void {
198✔
582
                $this->resolveFields($request)->registerRoutes($request, $router);
198✔
583
            });
198✔
584
        });
198✔
585
    }
586

587
    /**
588
     * Get the route middleware for the registered routes.
589
     */
590
    public function getRouteMiddleware(): array
591
    {
592
        return [
198✔
593
            Authorize::class.':_resource',
198✔
594
        ];
198✔
595
    }
596

597
    /**
598
     * Handle the route matched event.
599
     */
600
    public function routeMatched(RouteMatched $event): void
601
    {
602
        $event->route->defaults('resource', $this->getKey());
25✔
603

604
        $controller = $event->route->getController();
25✔
605

606
        $controller->middleware($this->getRouteMiddleware());
25✔
607

608
        if (! is_null($this->getPolicy())) {
25✔
UNCOV
609
            $controller->authorizeResource($this->getModel(), 'resourceModel');
×
610
        }
611

612
        $this->__routeMatched($event);
25✔
613
    }
614

615
    /**
616
     * Get the instance as an array.
617
     */
618
    public function toArray(): array
619
    {
620
        return [
4✔
621
            'icon' => $this->getIcon(),
4✔
622
            'key' => $this->getKey(),
4✔
623
            'model' => $this->getModel(),
4✔
624
            'modelName' => $this->getModelName(),
4✔
625
            'name' => $this->getName(),
4✔
626
            'uriKey' => $this->getUriKey(),
4✔
627
            'url' => $this->getUri(),
4✔
628
            'baseUrl' => $this->getUri(),
4✔
629
        ];
4✔
630
    }
631

632
    /**
633
     * Get the index representation of the resource.
634
     */
635
    public function toIndex(Request $request): array
636
    {
637
        return array_merge($this->toArray(), [
1✔
638
            'template' => 'root::resources.index',
1✔
639
            'title' => $this->getName(),
1✔
640
            'standaloneActions' => $this->resolveActions($request)
1✔
641
                ->authorized($request, $model = $this->getModelInstance())
1✔
642
                ->standalone()
1✔
643
                ->mapToForms($request, $model),
1✔
644
            'actions' => $this->resolveActions($request)
1✔
645
                ->authorized($request, $model = $this->getModelInstance())
1✔
646
                ->visible('index')
1✔
647
                ->standalone(false)
1✔
648
                ->mapToForms($request, $model),
1✔
649
            'data' => $this->paginate($request),
1✔
650
            'widgets' => $this->resolveWidgets($request)
1✔
651
                ->authorized($request)
1✔
652
                ->visible('index')
1✔
653
                ->mapToDisplay($request),
1✔
654
            'perPageOptions' => $this->getPerPageOptions(),
1✔
655
            'perPageKey' => $this->getPerPageKey(),
1✔
656
            'sortKey' => $this->getSortKey(),
1✔
657
            'filters' => $this->resolveFilters($request)
1✔
658
                ->authorized($request)
1✔
659
                ->renderable()
1✔
660
                ->map(static function (RenderableFilter $filter) use ($request, $model): array {
1✔
661
                    return $filter->toField()->toInput($request, $model);
1✔
662
                })
1✔
663
                ->all(),
1✔
664
            'activeFilters' => $this->resolveFilters($request)->active($request)->count(),
1✔
665
            'url' => $this->getUri(),
1✔
666
            'abilities' => $this->mapResourceAbilities($request),
1✔
667
        ]);
1✔
668
    }
669

670
    /**
671
     * Get the create representation of the resource.
672
     */
673
    public function toCreate(Request $request): array
674
    {
675
        return array_merge($this->toArray(), [
1✔
676
            'template' => 'root::resources.form',
1✔
677
            'title' => __('Create :resource', ['resource' => $this->getModelName()]),
1✔
678
            'model' => $model = $this->getModelInstance(),
1✔
679
            'action' => $this->getUri(),
1✔
680
            'method' => 'POST',
1✔
681
            'uploads' => $this->hasFileField($request),
1✔
682
            'fields' => $this->resolveFields($request)
1✔
683
                ->subResource(false)
1✔
684
                ->authorized($request, $model)
1✔
685
                ->visible('create')
1✔
686
                ->mapToInputs($request, $model),
1✔
687
            'abilities' => $this->mapResourceAbilities($request),
1✔
688
        ]);
1✔
689
    }
690

691
    /**
692
     * Get the edit representation of the resource.
693
     */
694
    public function toShow(Request $request, Model $model): array
695
    {
696
        return array_merge($this->toArray(), [
1✔
697
            'template' => 'root::resources.show',
1✔
698
            'title' => sprintf('%s: %s', $this->getModelName(), $this->modelTitle($model)),
1✔
699
            'model' => $model,
1✔
700
            'action' => $this->modelUrl($model),
1✔
701
            'fields' => $this->resolveFields($request)
1✔
702
                ->subResource(false)
1✔
703
                ->authorized($request, $model)
1✔
704
                ->visible('show')
1✔
705
                ->mapToDisplay($request, $model),
1✔
706
            'actions' => $this->resolveActions($request)
1✔
707
                ->authorized($request, $model)
1✔
708
                ->visible('show')
1✔
709
                ->standalone(false)
1✔
710
                ->mapToForms($request, $model),
1✔
711
            'widgets' => $this->resolveWidgets($request)
1✔
712
                ->authorized($request, $model)
1✔
713
                ->visible('show')
1✔
714
                ->mapToDisplay($request),
1✔
715
            'relations' => $this->resolveFields($request)
1✔
716
                ->subResource()
1✔
717
                ->authorized($request, $model)
1✔
718
                ->map(static function (Relation $relation) use ($request, $model): array {
1✔
719
                    return array_merge($relation->toSubResource($request, $model), [
1✔
720
                        'url' => URL::query($relation->modelUrl($model), $relation->parseQueryString($request->fullUrl())),
1✔
721
                    ]);
1✔
722
                }),
1✔
723
            'abilities' => array_merge(
1✔
724
                $this->mapResourceAbilities($request),
1✔
725
                $this->mapModelAbilities($request, $model)
1✔
726
            ),
1✔
727
        ]);
1✔
728
    }
729

730
    /**
731
     * Get the edit representation of the resource.
732
     */
733
    public function toEdit(Request $request, Model $model): array
734
    {
735
        return array_merge($this->toArray(), [
1✔
736
            'template' => 'root::resources.form',
1✔
737
            'title' => __('Edit :resource: :model', ['resource' => $this->getModelName(), 'model' => $this->modelTitle($model)]),
1✔
738
            'model' => $model,
1✔
739
            'action' => $this->modelUrl($model),
1✔
740
            'method' => 'PATCH',
1✔
741
            'uploads' => $this->hasFileField($request),
1✔
742
            'fields' => $this->resolveFields($request)
1✔
743
                ->subResource(false)
1✔
744
                ->authorized($request, $model)
1✔
745
                ->visible('update')
1✔
746
                ->mapToInputs($request, $model),
1✔
747
            'abilities' => array_merge(
1✔
748
                $this->mapResourceAbilities($request),
1✔
749
                $this->mapModelAbilities($request, $model)
1✔
750
            ),
1✔
751
        ]);
1✔
752
    }
753
}
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

© 2026 Coveralls, Inc