Skip to content

Commit

Permalink
feat: capabilities with builder pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas-frey committed Sep 25, 2024
1 parent be2c758 commit ec824e7
Show file tree
Hide file tree
Showing 38 changed files with 1,615 additions and 112 deletions.
30 changes: 0 additions & 30 deletions src/Auth/Capabilities.php

This file was deleted.

18 changes: 17 additions & 1 deletion src/Auth/Capability.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Guava\Capabilities\Auth;

enum Capability: string implements CapabilityRegistration
use \Guava\Capabilities\Contracts\Capability as CapabilityContract;

enum Capability: string implements CapabilityContract
{
case Access = 'viewAny';
case Create = 'create';
Expand All @@ -16,4 +18,18 @@ enum Capability: string implements CapabilityRegistration
case ForceDeleteBulk = 'forceDeleteBulk';
case Replicate = 'replicate';

public function model(): ?string
{
return null;
}

public function getModel(): ?string
{
return null;
}

public function getName(): string
{
return $this->value;
}
}
27 changes: 0 additions & 27 deletions src/Auth/Roles.php

This file was deleted.

14 changes: 14 additions & 0 deletions src/Builders/Builder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Guava\Capabilities\Builders;

use Illuminate\Database\Eloquent\Model;

interface Builder
{
public function assign(): static;

public function create(): static;

public function get(): ?Model;
}
122 changes: 122 additions & 0 deletions src/Builders/CapabilityBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

namespace Guava\Capabilities\Builders;

use Guava\Capabilities\Builders\Concerns\CanCreateIfNotExists;
use Guava\Capabilities\Builders\Concerns\HasAssignee;
use Guava\Capabilities\Builders\Concerns\HasTenant;
use Guava\Capabilities\Contracts\Capability as CapabilityContract;
use Guava\Capabilities\Facades\Capabilities;
use Guava\Capabilities\Models\Capability;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Stringable;

class CapabilityBuilder implements Builder
{
use CanCreateIfNotExists;
use HasAssignee;
use HasTenant;

protected CapabilityContract $configuration;

protected ?Capability $model = null;

public function __construct(string | CapabilityContract $capability, string|Model|null $model = null)
{
$this->configuration = static::configuration($capability instanceof CapabilityContract
? $capability->getName()
: $capability, $model);
// $this->configuration = $capability instanceof CapabilityContract
// ? $capability
// : static::configuration($capability, $model);
}

public function assign(?Model $assignee = null, ?Model $tenant = null): static
{
$assignee ??= $this->getAssignee();
if (! $assignee) {
return $this;
}

$tenant ??= $this->getTenant();

$model = $this->get();

if (! $model && $this->shouldCreateIfNotExists()) {
$model = $this->create()->get();
}

if ($model) {
$assignee->assignCapability($model, $tenant);
}

return $this;
}

public function create(): static
{
$this->model = Capabilities::capability()->create([
'name' => $this->configuration->getName(),
]);

return $this;
}

public function get(): ?Model
{
return $this->model ?? $this->find();
}

private function find(): ?Capability
{
return Capabilities::capability()->firstWhere([
'name' => $this->configuration->getName(),
]);
}

public static function of(string | CapabilityContract $capability, string | Model | null $model = null)
{
return app(static::class, ['capability' => $capability, 'model' => $model]);
}

private static function configuration(string $name, string | Model | null $model = null): CapabilityContract
{
$record = null;
if ($model instanceof Model) {
$record = $model;
$model = $record::class;
}

return new class($name, $model, $record) implements CapabilityContract
{
public function __construct(
private string $name,
private ?string $model = null,
private ?Model $record = null,
) {}

public function getName(): string
{
return str($this->name)
->when(
$this->model,
fn (Stringable $stringable) => $stringable
->prepend('.')
->prepend(str(class_basename($this->model))->kebab())
)
->when(
$this->record,
fn (Stringable $stringable) => $stringable
->append('.')
->append($this->record->getKey())
)
;
}

public function getModel(): ?string
{
return null;
}
};
}
}
20 changes: 20 additions & 0 deletions src/Builders/Concerns/CanCreateIfNotExists.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Guava\Capabilities\Builders\Concerns;

trait CanCreateIfNotExists
{
private bool $createIfNotExists = false;

public function createIfNotExists(bool $condition = true): static
{
$this->createIfNotExists = $condition;

return $this;
}

protected function shouldCreateIfNotExists(): bool
{
return $this->createIfNotExists;
}
}
22 changes: 22 additions & 0 deletions src/Builders/Concerns/HasAssignee.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Guava\Capabilities\Builders\Concerns;

use Illuminate\Database\Eloquent\Model;

trait HasAssignee
{
private ?Model $assignee = null;

public function assignee(Model $assignee): static
{
$this->assignee = $assignee;

return $this;
}

protected function getAssignee(): ?Model
{
return $this->assignee;
}
}
22 changes: 22 additions & 0 deletions src/Builders/Concerns/HasCapabilities.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Guava\Capabilities\Builders\Concerns;

use Illuminate\Support\Collection;

trait HasCapabilities
{
private ?Collection $capabilities = null;

public function capabilities(array | Collection $capabilities): static
{
$this->capabilities = collect($capabilities);

return $this;
}

protected function getCapabilities(): Collection
{
return $this->capabilities ?? collect();
}
}
28 changes: 28 additions & 0 deletions src/Builders/Concerns/HasOwner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Guava\Capabilities\Builders\Concerns;

use Guava\Capabilities\Exceptions\TenancyNotEnabledException;
use Illuminate\Database\Eloquent\Model;

trait HasOwner
{
private ?Model $owner = null;

public function owner(Model $owner): static
{
$this->owner = $owner;

return $this;
}

protected function getOwner(): ?Model
{
// TODO: Maybe refactor into 'capabilities.ownership' and differenciate between 'ownership' and 'tenancy'
if (! config('capabilities.tenancy', false)) {
throw TenancyNotEnabledException::make();
}

return $this->owner;
}
}
27 changes: 27 additions & 0 deletions src/Builders/Concerns/HasTenant.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Guava\Capabilities\Builders\Concerns;

use Guava\Capabilities\Exceptions\TenancyNotEnabledException;
use Illuminate\Database\Eloquent\Model;

trait HasTenant
{
private ?Model $tenant = null;

public function tenant(Model $tenant): static
{
$this->tenant = $tenant;

return $this;
}

protected function getTenant(): ?Model
{
if (! config('capabilities.tenancy', false)) {
throw TenancyNotEnabledException::make();
}

return $this->tenant;
}
}
Loading

0 comments on commit ec824e7

Please sign in to comment.