Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Auth\Access;
4
 
5
use Closure;
6
use Exception;
7
use Illuminate\Auth\Access\Events\GateEvaluated;
8
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
9
use Illuminate\Contracts\Container\Container;
10
use Illuminate\Contracts\Events\Dispatcher;
11
use Illuminate\Support\Arr;
12
use Illuminate\Support\Collection;
13
use Illuminate\Support\Str;
14
use InvalidArgumentException;
15
use ReflectionClass;
16
use ReflectionFunction;
17
 
18
class Gate implements GateContract
19
{
20
    use HandlesAuthorization;
21
 
22
    /**
23
     * The container instance.
24
     *
25
     * @var \Illuminate\Contracts\Container\Container
26
     */
27
    protected $container;
28
 
29
    /**
30
     * The user resolver callable.
31
     *
32
     * @var callable
33
     */
34
    protected $userResolver;
35
 
36
    /**
37
     * All of the defined abilities.
38
     *
39
     * @var array
40
     */
41
    protected $abilities = [];
42
 
43
    /**
44
     * All of the defined policies.
45
     *
46
     * @var array
47
     */
48
    protected $policies = [];
49
 
50
    /**
51
     * All of the registered before callbacks.
52
     *
53
     * @var array
54
     */
55
    protected $beforeCallbacks = [];
56
 
57
    /**
58
     * All of the registered after callbacks.
59
     *
60
     * @var array
61
     */
62
    protected $afterCallbacks = [];
63
 
64
    /**
65
     * All of the defined abilities using class@method notation.
66
     *
67
     * @var array
68
     */
69
    protected $stringCallbacks = [];
70
 
71
    /**
72
     * The callback to be used to guess policy names.
73
     *
74
     * @var callable|null
75
     */
76
    protected $guessPolicyNamesUsingCallback;
77
 
78
    /**
79
     * Create a new gate instance.
80
     *
81
     * @param  \Illuminate\Contracts\Container\Container  $container
82
     * @param  callable  $userResolver
83
     * @param  array  $abilities
84
     * @param  array  $policies
85
     * @param  array  $beforeCallbacks
86
     * @param  array  $afterCallbacks
87
     * @param  callable|null  $guessPolicyNamesUsingCallback
88
     * @return void
89
     */
90
    public function __construct(Container $container, callable $userResolver, array $abilities = [],
91
                                array $policies = [], array $beforeCallbacks = [], array $afterCallbacks = [],
92
                                callable $guessPolicyNamesUsingCallback = null)
93
    {
94
        $this->policies = $policies;
95
        $this->container = $container;
96
        $this->abilities = $abilities;
97
        $this->userResolver = $userResolver;
98
        $this->afterCallbacks = $afterCallbacks;
99
        $this->beforeCallbacks = $beforeCallbacks;
100
        $this->guessPolicyNamesUsingCallback = $guessPolicyNamesUsingCallback;
101
    }
102
 
103
    /**
104
     * Determine if a given ability has been defined.
105
     *
106
     * @param  string|array  $ability
107
     * @return bool
108
     */
109
    public function has($ability)
110
    {
111
        $abilities = is_array($ability) ? $ability : func_get_args();
112
 
113
        foreach ($abilities as $ability) {
114
            if (! isset($this->abilities[$ability])) {
115
                return false;
116
            }
117
        }
118
 
119
        return true;
120
    }
121
 
122
    /**
123
     * Perform an on-demand authorization check. Throw an authorization exception if the condition or callback is false.
124
     *
125
     * @param  \Illuminate\Auth\Access\Response|\Closure|bool  $condition
126
     * @param  string|null  $message
127
     * @param  string|null  $code
128
     * @return \Illuminate\Auth\Access\Response
129
     *
130
     * @throws \Illuminate\Auth\Access\AuthorizationException
131
     */
132
    public function allowIf($condition, $message = null, $code = null)
133
    {
134
        return $this->authorizeOnDemand($condition, $message, $code, true);
135
    }
136
 
137
    /**
138
     * Perform an on-demand authorization check. Throw an authorization exception if the condition or callback is true.
139
     *
140
     * @param  \Illuminate\Auth\Access\Response|\Closure|bool  $condition
141
     * @param  string|null  $message
142
     * @param  string|null  $code
143
     * @return \Illuminate\Auth\Access\Response
144
     *
145
     * @throws \Illuminate\Auth\Access\AuthorizationException
146
     */
147
    public function denyIf($condition, $message = null, $code = null)
148
    {
149
        return $this->authorizeOnDemand($condition, $message, $code, false);
150
    }
151
 
152
    /**
153
     * Authorize a given condition or callback.
154
     *
155
     * @param  \Illuminate\Auth\Access\Response|\Closure|bool  $condition
156
     * @param  string|null  $message
157
     * @param  string|null  $code
158
     * @param  bool  $allowWhenResponseIs
159
     * @return \Illuminate\Auth\Access\Response
160
     *
161
     * @throws \Illuminate\Auth\Access\AuthorizationException
162
     */
163
    protected function authorizeOnDemand($condition, $message, $code, $allowWhenResponseIs)
164
    {
165
        $user = $this->resolveUser();
166
 
167
        if ($condition instanceof Closure) {
168
            $response = $this->canBeCalledWithUser($user, $condition)
169
                            ? $condition($user)
170
                            : new Response(false, $message, $code);
171
        } else {
172
            $response = $condition;
173
        }
174
 
175
        return with($response instanceof Response ? $response : new Response(
176
            (bool) $response === $allowWhenResponseIs, $message, $code
177
        ))->authorize();
178
    }
179
 
180
    /**
181
     * Define a new ability.
182
     *
183
     * @param  string  $ability
184
     * @param  callable|array|string  $callback
185
     * @return $this
186
     *
187
     * @throws \InvalidArgumentException
188
     */
189
    public function define($ability, $callback)
190
    {
191
        if (is_array($callback) && isset($callback[0]) && is_string($callback[0])) {
192
            $callback = $callback[0].'@'.$callback[1];
193
        }
194
 
195
        if (is_callable($callback)) {
196
            $this->abilities[$ability] = $callback;
197
        } elseif (is_string($callback)) {
198
            $this->stringCallbacks[$ability] = $callback;
199
 
200
            $this->abilities[$ability] = $this->buildAbilityCallback($ability, $callback);
201
        } else {
202
            throw new InvalidArgumentException("Callback must be a callable, callback array, or a 'Class@method' string.");
203
        }
204
 
205
        return $this;
206
    }
207
 
208
    /**
209
     * Define abilities for a resource.
210
     *
211
     * @param  string  $name
212
     * @param  string  $class
213
     * @param  array|null  $abilities
214
     * @return $this
215
     */
216
    public function resource($name, $class, array $abilities = null)
217
    {
218
        $abilities = $abilities ?: [
219
            'viewAny' => 'viewAny',
220
            'view' => 'view',
221
            'create' => 'create',
222
            'update' => 'update',
223
            'delete' => 'delete',
224
        ];
225
 
226
        foreach ($abilities as $ability => $method) {
227
            $this->define($name.'.'.$ability, $class.'@'.$method);
228
        }
229
 
230
        return $this;
231
    }
232
 
233
    /**
234
     * Create the ability callback for a callback string.
235
     *
236
     * @param  string  $ability
237
     * @param  string  $callback
238
     * @return \Closure
239
     */
240
    protected function buildAbilityCallback($ability, $callback)
241
    {
242
        return function () use ($ability, $callback) {
243
            if (str_contains($callback, '@')) {
244
                [$class, $method] = Str::parseCallback($callback);
245
            } else {
246
                $class = $callback;
247
            }
248
 
249
            $policy = $this->resolvePolicy($class);
250
 
251
            $arguments = func_get_args();
252
 
253
            $user = array_shift($arguments);
254
 
255
            $result = $this->callPolicyBefore(
256
                $policy, $user, $ability, $arguments
257
            );
258
 
259
            if (! is_null($result)) {
260
                return $result;
261
            }
262
 
263
            return isset($method)
264
                    ? $policy->{$method}(...func_get_args())
265
                    : $policy(...func_get_args());
266
        };
267
    }
268
 
269
    /**
270
     * Define a policy class for a given class type.
271
     *
272
     * @param  string  $class
273
     * @param  string  $policy
274
     * @return $this
275
     */
276
    public function policy($class, $policy)
277
    {
278
        $this->policies[$class] = $policy;
279
 
280
        return $this;
281
    }
282
 
283
    /**
284
     * Register a callback to run before all Gate checks.
285
     *
286
     * @param  callable  $callback
287
     * @return $this
288
     */
289
    public function before(callable $callback)
290
    {
291
        $this->beforeCallbacks[] = $callback;
292
 
293
        return $this;
294
    }
295
 
296
    /**
297
     * Register a callback to run after all Gate checks.
298
     *
299
     * @param  callable  $callback
300
     * @return $this
301
     */
302
    public function after(callable $callback)
303
    {
304
        $this->afterCallbacks[] = $callback;
305
 
306
        return $this;
307
    }
308
 
309
    /**
310
     * Determine if the given ability should be granted for the current user.
311
     *
312
     * @param  string  $ability
313
     * @param  array|mixed  $arguments
314
     * @return bool
315
     */
316
    public function allows($ability, $arguments = [])
317
    {
318
        return $this->check($ability, $arguments);
319
    }
320
 
321
    /**
322
     * Determine if the given ability should be denied for the current user.
323
     *
324
     * @param  string  $ability
325
     * @param  array|mixed  $arguments
326
     * @return bool
327
     */
328
    public function denies($ability, $arguments = [])
329
    {
330
        return ! $this->allows($ability, $arguments);
331
    }
332
 
333
    /**
334
     * Determine if all of the given abilities should be granted for the current user.
335
     *
336
     * @param  iterable|string  $abilities
337
     * @param  array|mixed  $arguments
338
     * @return bool
339
     */
340
    public function check($abilities, $arguments = [])
341
    {
342
        return collect($abilities)->every(
343
            fn ($ability) => $this->inspect($ability, $arguments)->allowed()
344
        );
345
    }
346
 
347
    /**
348
     * Determine if any one of the given abilities should be granted for the current user.
349
     *
350
     * @param  iterable|string  $abilities
351
     * @param  array|mixed  $arguments
352
     * @return bool
353
     */
354
    public function any($abilities, $arguments = [])
355
    {
356
        return collect($abilities)->contains(fn ($ability) => $this->check($ability, $arguments));
357
    }
358
 
359
    /**
360
     * Determine if all of the given abilities should be denied for the current user.
361
     *
362
     * @param  iterable|string  $abilities
363
     * @param  array|mixed  $arguments
364
     * @return bool
365
     */
366
    public function none($abilities, $arguments = [])
367
    {
368
        return ! $this->any($abilities, $arguments);
369
    }
370
 
371
    /**
372
     * Determine if the given ability should be granted for the current user.
373
     *
374
     * @param  string  $ability
375
     * @param  array|mixed  $arguments
376
     * @return \Illuminate\Auth\Access\Response
377
     *
378
     * @throws \Illuminate\Auth\Access\AuthorizationException
379
     */
380
    public function authorize($ability, $arguments = [])
381
    {
382
        return $this->inspect($ability, $arguments)->authorize();
383
    }
384
 
385
    /**
386
     * Inspect the user for the given ability.
387
     *
388
     * @param  string  $ability
389
     * @param  array|mixed  $arguments
390
     * @return \Illuminate\Auth\Access\Response
391
     */
392
    public function inspect($ability, $arguments = [])
393
    {
394
        try {
395
            $result = $this->raw($ability, $arguments);
396
 
397
            if ($result instanceof Response) {
398
                return $result;
399
            }
400
 
401
            return $result ? Response::allow() : Response::deny();
402
        } catch (AuthorizationException $e) {
403
            return $e->toResponse();
404
        }
405
    }
406
 
407
    /**
408
     * Get the raw result from the authorization callback.
409
     *
410
     * @param  string  $ability
411
     * @param  array|mixed  $arguments
412
     * @return mixed
413
     *
414
     * @throws \Illuminate\Auth\Access\AuthorizationException
415
     */
416
    public function raw($ability, $arguments = [])
417
    {
418
        $arguments = Arr::wrap($arguments);
419
 
420
        $user = $this->resolveUser();
421
 
422
        // First we will call the "before" callbacks for the Gate. If any of these give
423
        // back a non-null response, we will immediately return that result in order
424
        // to let the developers override all checks for some authorization cases.
425
        $result = $this->callBeforeCallbacks(
426
            $user, $ability, $arguments
427
        );
428
 
429
        if (is_null($result)) {
430
            $result = $this->callAuthCallback($user, $ability, $arguments);
431
        }
432
 
433
        // After calling the authorization callback, we will call the "after" callbacks
434
        // that are registered with the Gate, which allows a developer to do logging
435
        // if that is required for this application. Then we'll return the result.
436
        return tap($this->callAfterCallbacks(
437
            $user, $ability, $arguments, $result
438
        ), function ($result) use ($user, $ability, $arguments) {
439
            $this->dispatchGateEvaluatedEvent($user, $ability, $arguments, $result);
440
        });
441
    }
442
 
443
    /**
444
     * Determine whether the callback/method can be called with the given user.
445
     *
446
     * @param  \Illuminate\Contracts\Auth\Authenticatable|null  $user
447
     * @param  \Closure|string|array  $class
448
     * @param  string|null  $method
449
     * @return bool
450
     */
451
    protected function canBeCalledWithUser($user, $class, $method = null)
452
    {
453
        if (! is_null($user)) {
454
            return true;
455
        }
456
 
457
        if (! is_null($method)) {
458
            return $this->methodAllowsGuests($class, $method);
459
        }
460
 
461
        if (is_array($class)) {
462
            $className = is_string($class[0]) ? $class[0] : get_class($class[0]);
463
 
464
            return $this->methodAllowsGuests($className, $class[1]);
465
        }
466
 
467
        return $this->callbackAllowsGuests($class);
468
    }
469
 
470
    /**
471
     * Determine if the given class method allows guests.
472
     *
473
     * @param  string  $class
474
     * @param  string  $method
475
     * @return bool
476
     */
477
    protected function methodAllowsGuests($class, $method)
478
    {
479
        try {
480
            $reflection = new ReflectionClass($class);
481
 
482
            $method = $reflection->getMethod($method);
483
        } catch (Exception $e) {
484
            return false;
485
        }
486
 
487
        if ($method) {
488
            $parameters = $method->getParameters();
489
 
490
            return isset($parameters[0]) && $this->parameterAllowsGuests($parameters[0]);
491
        }
492
 
493
        return false;
494
    }
495
 
496
    /**
497
     * Determine if the callback allows guests.
498
     *
499
     * @param  callable  $callback
500
     * @return bool
501
     *
502
     * @throws \ReflectionException
503
     */
504
    protected function callbackAllowsGuests($callback)
505
    {
506
        $parameters = (new ReflectionFunction($callback))->getParameters();
507
 
508
        return isset($parameters[0]) && $this->parameterAllowsGuests($parameters[0]);
509
    }
510
 
511
    /**
512
     * Determine if the given parameter allows guests.
513
     *
514
     * @param  \ReflectionParameter  $parameter
515
     * @return bool
516
     */
517
    protected function parameterAllowsGuests($parameter)
518
    {
519
        return ($parameter->hasType() && $parameter->allowsNull()) ||
520
               ($parameter->isDefaultValueAvailable() && is_null($parameter->getDefaultValue()));
521
    }
522
 
523
    /**
524
     * Resolve and call the appropriate authorization callback.
525
     *
526
     * @param  \Illuminate\Contracts\Auth\Authenticatable|null  $user
527
     * @param  string  $ability
528
     * @param  array  $arguments
529
     * @return bool
530
     */
531
    protected function callAuthCallback($user, $ability, array $arguments)
532
    {
533
        $callback = $this->resolveAuthCallback($user, $ability, $arguments);
534
 
535
        return $callback($user, ...$arguments);
536
    }
537
 
538
    /**
539
     * Call all of the before callbacks and return if a result is given.
540
     *
541
     * @param  \Illuminate\Contracts\Auth\Authenticatable|null  $user
542
     * @param  string  $ability
543
     * @param  array  $arguments
544
     * @return bool|null
545
     */
546
    protected function callBeforeCallbacks($user, $ability, array $arguments)
547
    {
548
        foreach ($this->beforeCallbacks as $before) {
549
            if (! $this->canBeCalledWithUser($user, $before)) {
550
                continue;
551
            }
552
 
553
            if (! is_null($result = $before($user, $ability, $arguments))) {
554
                return $result;
555
            }
556
        }
557
    }
558
 
559
    /**
560
     * Call all of the after callbacks with check result.
561
     *
562
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
563
     * @param  string  $ability
564
     * @param  array  $arguments
565
     * @param  bool  $result
566
     * @return bool|null
567
     */
568
    protected function callAfterCallbacks($user, $ability, array $arguments, $result)
569
    {
570
        foreach ($this->afterCallbacks as $after) {
571
            if (! $this->canBeCalledWithUser($user, $after)) {
572
                continue;
573
            }
574
 
575
            $afterResult = $after($user, $ability, $result, $arguments);
576
 
577
            $result ??= $afterResult;
578
        }
579
 
580
        return $result;
581
    }
582
 
583
    /**
584
     * Dispatch a gate evaluation event.
585
     *
586
     * @param  \Illuminate\Contracts\Auth\Authenticatable|null  $user
587
     * @param  string  $ability
588
     * @param  array  $arguments
589
     * @param  bool|null  $result
590
     * @return void
591
     */
592
    protected function dispatchGateEvaluatedEvent($user, $ability, array $arguments, $result)
593
    {
594
        if ($this->container->bound(Dispatcher::class)) {
595
            $this->container->make(Dispatcher::class)->dispatch(
596
                new GateEvaluated($user, $ability, $result, $arguments)
597
            );
598
        }
599
    }
600
 
601
    /**
602
     * Resolve the callable for the given ability and arguments.
603
     *
604
     * @param  \Illuminate\Contracts\Auth\Authenticatable|null  $user
605
     * @param  string  $ability
606
     * @param  array  $arguments
607
     * @return callable
608
     */
609
    protected function resolveAuthCallback($user, $ability, array $arguments)
610
    {
611
        if (isset($arguments[0]) &&
612
            ! is_null($policy = $this->getPolicyFor($arguments[0])) &&
613
            $callback = $this->resolvePolicyCallback($user, $ability, $arguments, $policy)) {
614
            return $callback;
615
        }
616
 
617
        if (isset($this->stringCallbacks[$ability])) {
618
            [$class, $method] = Str::parseCallback($this->stringCallbacks[$ability]);
619
 
620
            if ($this->canBeCalledWithUser($user, $class, $method ?: '__invoke')) {
621
                return $this->abilities[$ability];
622
            }
623
        }
624
 
625
        if (isset($this->abilities[$ability]) &&
626
            $this->canBeCalledWithUser($user, $this->abilities[$ability])) {
627
            return $this->abilities[$ability];
628
        }
629
 
630
        return function () {
631
            //
632
        };
633
    }
634
 
635
    /**
636
     * Get a policy instance for a given class.
637
     *
638
     * @param  object|string  $class
639
     * @return mixed
640
     */
641
    public function getPolicyFor($class)
642
    {
643
        if (is_object($class)) {
644
            $class = get_class($class);
645
        }
646
 
647
        if (! is_string($class)) {
648
            return;
649
        }
650
 
651
        if (isset($this->policies[$class])) {
652
            return $this->resolvePolicy($this->policies[$class]);
653
        }
654
 
655
        foreach ($this->guessPolicyName($class) as $guessedPolicy) {
656
            if (class_exists($guessedPolicy)) {
657
                return $this->resolvePolicy($guessedPolicy);
658
            }
659
        }
660
 
661
        foreach ($this->policies as $expected => $policy) {
662
            if (is_subclass_of($class, $expected)) {
663
                return $this->resolvePolicy($policy);
664
            }
665
        }
666
    }
667
 
668
    /**
669
     * Guess the policy name for the given class.
670
     *
671
     * @param  string  $class
672
     * @return array
673
     */
674
    protected function guessPolicyName($class)
675
    {
676
        if ($this->guessPolicyNamesUsingCallback) {
677
            return Arr::wrap(call_user_func($this->guessPolicyNamesUsingCallback, $class));
678
        }
679
 
680
        $classDirname = str_replace('/', '\\', dirname(str_replace('\\', '/', $class)));
681
 
682
        $classDirnameSegments = explode('\\', $classDirname);
683
 
684
        return Arr::wrap(Collection::times(count($classDirnameSegments), function ($index) use ($class, $classDirnameSegments) {
685
            $classDirname = implode('\\', array_slice($classDirnameSegments, 0, $index));
686
 
687
            return $classDirname.'\\Policies\\'.class_basename($class).'Policy';
688
        })->reverse()->values()->first(function ($class) {
689
            return class_exists($class);
690
        }) ?: [$classDirname.'\\Policies\\'.class_basename($class).'Policy']);
691
    }
692
 
693
    /**
694
     * Specify a callback to be used to guess policy names.
695
     *
696
     * @param  callable  $callback
697
     * @return $this
698
     */
699
    public function guessPolicyNamesUsing(callable $callback)
700
    {
701
        $this->guessPolicyNamesUsingCallback = $callback;
702
 
703
        return $this;
704
    }
705
 
706
    /**
707
     * Build a policy class instance of the given type.
708
     *
709
     * @param  object|string  $class
710
     * @return mixed
711
     *
712
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
713
     */
714
    public function resolvePolicy($class)
715
    {
716
        return $this->container->make($class);
717
    }
718
 
719
    /**
720
     * Resolve the callback for a policy check.
721
     *
722
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
723
     * @param  string  $ability
724
     * @param  array  $arguments
725
     * @param  mixed  $policy
726
     * @return bool|callable
727
     */
728
    protected function resolvePolicyCallback($user, $ability, array $arguments, $policy)
729
    {
730
        if (! is_callable([$policy, $this->formatAbilityToMethod($ability)])) {
731
            return false;
732
        }
733
 
734
        return function () use ($user, $ability, $arguments, $policy) {
735
            // This callback will be responsible for calling the policy's before method and
736
            // running this policy method if necessary. This is used to when objects are
737
            // mapped to policy objects in the user's configurations or on this class.
738
            $result = $this->callPolicyBefore(
739
                $policy, $user, $ability, $arguments
740
            );
741
 
742
            // When we receive a non-null result from this before method, we will return it
743
            // as the "final" results. This will allow developers to override the checks
744
            // in this policy to return the result for all rules defined in the class.
745
            if (! is_null($result)) {
746
                return $result;
747
            }
748
 
749
            $method = $this->formatAbilityToMethod($ability);
750
 
751
            return $this->callPolicyMethod($policy, $method, $user, $arguments);
752
        };
753
    }
754
 
755
    /**
756
     * Call the "before" method on the given policy, if applicable.
757
     *
758
     * @param  mixed  $policy
759
     * @param  \Illuminate\Contracts\Auth\Authenticatable  $user
760
     * @param  string  $ability
761
     * @param  array  $arguments
762
     * @return mixed
763
     */
764
    protected function callPolicyBefore($policy, $user, $ability, $arguments)
765
    {
766
        if (! method_exists($policy, 'before')) {
767
            return;
768
        }
769
 
770
        if ($this->canBeCalledWithUser($user, $policy, 'before')) {
771
            return $policy->before($user, $ability, ...$arguments);
772
        }
773
    }
774
 
775
    /**
776
     * Call the appropriate method on the given policy.
777
     *
778
     * @param  mixed  $policy
779
     * @param  string  $method
780
     * @param  \Illuminate\Contracts\Auth\Authenticatable|null  $user
781
     * @param  array  $arguments
782
     * @return mixed
783
     */
784
    protected function callPolicyMethod($policy, $method, $user, array $arguments)
785
    {
786
        // If this first argument is a string, that means they are passing a class name
787
        // to the policy. We will remove the first argument from this argument array
788
        // because this policy already knows what type of models it can authorize.
789
        if (isset($arguments[0]) && is_string($arguments[0])) {
790
            array_shift($arguments);
791
        }
792
 
793
        if (! is_callable([$policy, $method])) {
794
            return;
795
        }
796
 
797
        if ($this->canBeCalledWithUser($user, $policy, $method)) {
798
            return $policy->{$method}($user, ...$arguments);
799
        }
800
    }
801
 
802
    /**
803
     * Format the policy ability into a method name.
804
     *
805
     * @param  string  $ability
806
     * @return string
807
     */
808
    protected function formatAbilityToMethod($ability)
809
    {
810
        return str_contains($ability, '-') ? Str::camel($ability) : $ability;
811
    }
812
 
813
    /**
814
     * Get a gate instance for the given user.
815
     *
816
     * @param  \Illuminate\Contracts\Auth\Authenticatable|mixed  $user
817
     * @return static
818
     */
819
    public function forUser($user)
820
    {
821
        $callback = fn () => $user;
822
 
823
        return new static(
824
            $this->container, $callback, $this->abilities,
825
            $this->policies, $this->beforeCallbacks, $this->afterCallbacks,
826
            $this->guessPolicyNamesUsingCallback
827
        );
828
    }
829
 
830
    /**
831
     * Resolve the user from the user resolver.
832
     *
833
     * @return mixed
834
     */
835
    protected function resolveUser()
836
    {
837
        return call_user_func($this->userResolver);
838
    }
839
 
840
    /**
841
     * Get all of the defined abilities.
842
     *
843
     * @return array
844
     */
845
    public function abilities()
846
    {
847
        return $this->abilities;
848
    }
849
 
850
    /**
851
     * Get all of the defined policies.
852
     *
853
     * @return array
854
     */
855
    public function policies()
856
    {
857
        return $this->policies;
858
    }
859
 
860
    /**
861
     * Set the container instance used by the gate.
862
     *
863
     * @param  \Illuminate\Contracts\Container\Container  $container
864
     * @return $this
865
     */
866
    public function setContainer(Container $container)
867
    {
868
        $this->container = $container;
869
 
870
        return $this;
871
    }
872
}