File "FindsAndCreatesAbilities.php"
Full Path: /home/pulsehostuk9/public_html/invoicer.pulsehost.co.uk/vendor/silber/bouncer/src/Conductors/Concerns/FindsAndCreatesAbilities.php
File size: 6.75 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace Silber\Bouncer\Conductors\Concerns;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use InvalidArgumentException;
use Silber\Bouncer\Database\Models;
use Silber\Bouncer\Helpers;
trait FindsAndCreatesAbilities
{
/**
* Get the IDs of the provided abilities.
*
* @param \Illuminate\Database\Eloquent\model|array|int $abilities
* @param \Illuminate\Database\Eloquent\Model|string|array|null $model
* @return array
*/
protected function getAbilityIds($abilities, $model = null, array $attributes = [])
{
if ($abilities instanceof Model) {
return [$abilities->getKey()];
}
if (! is_null($model)) {
return $this->getModelAbilityKeys($abilities, $model, $attributes);
}
if (Helpers::isAssociativeArray($abilities)) {
return $this->getAbilityIdsFromMap($abilities, $attributes);
}
if (! is_array($abilities) && ! $abilities instanceof Collection) {
$abilities = [$abilities];
}
return $this->getAbilityIdsFromArray($abilities, $attributes);
}
/**
* Get the ability IDs for the given map.
*
* The map should use the ['ability-name' => Entity::class] format.
*
* @return array
*/
protected function getAbilityIdsFromMap(array $map, array $attributes)
{
[$map, $list] = Helpers::partition($map, function ($value, $key) {
return ! is_int($key);
});
return $map->map(function ($entity, $ability) use ($attributes) {
return $this->getAbilityIds($ability, $entity, $attributes);
})->collapse()->merge($this->getAbilityIdsFromArray($list, $attributes))->all();
}
/**
* Get the ability IDs from the provided array, creating the ones that don't exist.
*
* @param iterable $abilities
* @return array
*/
protected function getAbilityIdsFromArray($abilities, array $attributes)
{
$groups = Helpers::groupModelsAndIdentifiersByType($abilities);
$keyName = Models::ability()->getKeyName();
$groups['strings'] = $this->abilitiesByName($groups['strings'], $attributes)
->pluck($keyName)->all();
$groups['models'] = Arr::pluck($groups['models'], $keyName);
return Arr::collapse($groups);
}
/**
* Get the abilities for the given model ability descriptors.
*
* @param array|string $abilities
* @param \Illuminate\Database\Eloquent\Model|string|array $model
* @return array
*/
protected function getModelAbilityKeys($abilities, $model, array $attributes)
{
$abilities = Collection::make(is_array($abilities) ? $abilities : [$abilities]);
$models = Collection::make(is_array($model) ? $model : [$model]);
return $abilities->map(function ($ability) use ($models, $attributes) {
return $models->map(function ($model) use ($ability, $attributes) {
return $this->getModelAbility($ability, $model, $attributes)->getKey();
});
})->collapse()->all();
}
/**
* Get an ability for the given entity.
*
* @param string $ability
* @param \Illuminate\Database\Eloquent\Model|string $entity
* @return \Silber\Bouncer\Database\Ability
*/
protected function getModelAbility($ability, $entity, array $attributes)
{
$entity = $this->getEntityInstance($entity);
$existing = $this->findAbility($ability, $entity, $attributes);
return $existing ?: $this->createAbility($ability, $entity, $attributes);
}
/**
* Find the ability for the given entity.
*
* @param string $ability
* @param \Illuminate\Database\Eloquent\Model|string $entity
* @param array $attributes
* @return \Silber\Bouncer\Database\Ability|null
*/
protected function findAbility($ability, $entity, $attributes)
{
$onlyOwned = isset($attributes['only_owned']) ? $attributes['only_owned'] : false;
$query = Models::ability()
->where('name', $ability)
->forModel($entity, true)
->where('only_owned', $onlyOwned);
return Models::scope()->applyToModelQuery($query)->first();
}
/**
* Create an ability for the given entity.
*
* @param string $ability
* @param \Illuminate\Database\Eloquent\Model|string $entity
* @param array $attributes
* @return \Silber\Bouncer\Database\Ability
*/
protected function createAbility($ability, $entity, $attributes)
{
return Models::ability()->createForModel($entity, $attributes + [
'name' => $ability,
]);
}
/**
* Get an instance of the given model.
*
* @param \Illuminate\Database\Eloquent\Model|string $model
* @return \Illuminate\Database\Eloquent\Model|string
*/
protected function getEntityInstance($model)
{
if ($model === '*') {
return '*';
}
if (! $model instanceof Model) {
return new $model;
}
// Creating an ability for a non-existent model gives the authority that
// ability on all instances of that model. If the developer passed in
// a model instance that does not exist, it is probably a mistake.
if (! $model->exists) {
throw new InvalidArgumentException(
'The model does not exist. To edit access to all models, use the class name instead'
);
}
return $model;
}
/**
* Get or create abilities by their name.
*
* @param array|string $abilities
* @param array $attributes
* @return \Illuminate\Support\Collection
*/
protected function abilitiesByName($abilities, $attributes = [])
{
$abilities = array_unique(is_array($abilities) ? $abilities : [$abilities]);
if (empty($abilities)) {
return new Collection;
}
$existing = Models::ability()->simpleAbility()->whereIn('name', $abilities)->get();
return $existing->merge($this->createMissingAbilities(
$existing, $abilities, $attributes
));
}
/**
* Create the non-existant abilities by name.
*
* @param \Illuminate\Database\Eloquent\Collection $existing
* @param string[] $abilities
* @param array $attributes
* @return array
*/
protected function createMissingAbilities($existing, array $abilities, $attributes = [])
{
$missing = array_diff($abilities, $existing->pluck('name')->all());
return array_map(function ($ability) use ($attributes) {
return Models::ability()->create($attributes + ['name' => $ability]);
}, $missing);
}
}