Skip to content

Commit

Permalink
Refactor the gate.
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorotwell committed Dec 23, 2016
1 parent 7b48bfc commit 5c4541b
Showing 1 changed file with 81 additions and 44 deletions.
125 changes: 81 additions & 44 deletions src/Illuminate/Auth/Access/Gate.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ class Gate implements GateContract
* @param array $afterCallbacks
* @return void
*/
public function __construct(Container $container, callable $userResolver, array $abilities = [], array $policies = [], array $beforeCallbacks = [], array $afterCallbacks = [])
public function __construct(Container $container, callable $userResolver, array $abilities = [],
array $policies = [], array $beforeCallbacks = [], array $afterCallbacks = [])
{
$this->policies = $policies;
$this->container = $container;
Expand Down Expand Up @@ -225,7 +226,7 @@ public function authorize($ability, $arguments = [])
}

/**
* Get the raw result for the given ability for the current user.
* Get the raw result from the authorization callback.
*
* @param string $ability
* @param array|mixed $arguments
Expand All @@ -239,10 +240,20 @@ protected function raw($ability, $arguments = [])

$arguments = is_array($arguments) ? $arguments : [$arguments];

if (is_null($result = $this->callBeforeCallbacks($user, $ability, $arguments))) {
// First we will call the "before" callbacks for the Gate. If any of these give
// back a non-null response, we will immediately return that result in order
// to let the developers override all checks for some authorization cases.
$result = $this->callBeforeCallbacks(
$user, $ability, $arguments
);

if (is_null($result)) {
$result = $this->callAuthCallback($user, $ability, $arguments);
}

// After calling the authorization callback, we will call the "after" callbacks
// that are registered with the Gate, which allows a developer to do logging
// if that is required for this application. Then we'll return the result.
$this->callAfterCallbacks(
$user, $ability, $arguments, $result
);
Expand Down Expand Up @@ -313,9 +324,7 @@ protected function callAfterCallbacks($user, $ability, array $arguments, $result
protected function resolveAuthCallback($user, $ability, array $arguments)
{
if (isset($arguments[0])) {
$policy = $this->getPolicyFor($arguments[0]);

if ($policy !== null) {
if (! is_null($policy = $this->getPolicyFor($arguments[0]))) {
return $this->resolvePolicyCallback($user, $ability, $arguments, $policy);
}
}
Expand All @@ -329,6 +338,40 @@ protected function resolveAuthCallback($user, $ability, array $arguments)
}
}

/**
* Get a policy instance for a given class.
*
* @param object|string $class
* @return mixed
*/
public function getPolicyFor($class)
{
if (is_object($class)) {
$class = get_class($class);
}

if (isset($this->policies[$class])) {
return $this->resolvePolicy($this->policies[$class]);
}

foreach ($this->policies as $expected => $policy) {
if (is_subclass_of($class, $expected)) {
return $this->resolvePolicy($policy);
}
}
}

/**
* Build a policy class instance of the given type.
*
* @param object|string $class
* @return mixed
*/
public function resolvePolicy($class)
{
return $this->container->make($class);
}

/**
* Resolve the callback for a policy check.
*
Expand All @@ -341,66 +384,60 @@ protected function resolveAuthCallback($user, $ability, array $arguments)
protected function resolvePolicyCallback($user, $ability, array $arguments, $policy)
{
return function () use ($user, $ability, $arguments, $policy) {
// If we receive a non-null result from the before method, we will return it
// as the final result. This will allow developers to override the checks
// in the policy to return a result for all rules defined in the class.
if (method_exists($policy, 'before')) {
if (! is_null($result = $policy->before($user, $ability, ...$arguments))) {
return $result;
}
// This callback will be responsible for calling the policy's before method and
// running this policy method if necessary. This is used to when objects are
// mapped to policy objects in the user's configurations or on this class.
$result = $this->callPolicyBefore(
$policy, $user, $ability, $arguments
);

// When we receive a non-null result from this before method, we will return it
// as the "final" results. This will allow developers to override the checks
// in this policy to return the result for all rules defined in the class.
if (! is_null($result)) {
return $result;
}

if (strpos($ability, '-') !== false) {
$ability = Str::camel($ability);
}
$ability = $this->formatAbilityToMethod($ability);

// If the first argument is a string, that means they are passing a class name
// to the policy. We will remove the first argument from this argument list
// because the policy already knows what type of models it can authorize.
// If this first argument is a string, that means they are passing a class name
// to the policy. We will remove the first argument from this argument array
// because this policy already knows what type of models it can authorize.
if (isset($arguments[0]) && is_string($arguments[0])) {
array_shift($arguments);
}

if (! is_callable([$policy, $ability])) {
return false;
}

return $policy->{$ability}($user, ...$arguments);
return is_callable([$policy, $ability])
? $policy->{$ability}($user, ...$arguments)
: false;
};
}

/**
* Get a policy instance for a given class.
* Call the "before" method on the given policy, if applicable.
*
* @param object|string $class
* @param mixed $policy
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $ability
* @param array $arguments
* @return mixed
*/
public function getPolicyFor($class)
protected function callPolicyBefore($policy, $user, $ability, $arguments)
{
if (is_object($class)) {
$class = get_class($class);
}

if (isset($this->policies[$class])) {
return $this->resolvePolicy($this->policies[$class]);
}

foreach ($this->policies as $expected => $policy) {
if (is_subclass_of($class, $expected)) {
return $this->resolvePolicy($policy);
}
if (method_exists($policy, 'before')) {
return $policy->before($user, $ability, ...$arguments);
}
}

/**
* Build a policy class instance of the given type.
* Format the policy ability into a method name.
*
* @param object|string $class
* @return mixed
* @param string $ability
* @return string
*/
public function resolvePolicy($class)
protected function formatAbilityToMethod($ability)
{
return $this->container->make($class);
return strpos($ability, '-') !== false ? Str::camel($ability) : $ability;
}

/**
Expand Down

0 comments on commit 5c4541b

Please sign in to comment.