Skip to content

Commit

Permalink
Merge pull request #16 from Lomkit/feature/directives
Browse files Browse the repository at this point in the history
Feature/instructions
  • Loading branch information
GautierDele authored Aug 17, 2023
2 parents 1307cfe + f758d35 commit 82d3a3d
Show file tree
Hide file tree
Showing 24 changed files with 1,144 additions and 116 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,9 @@ TODO

## Roadmap for the end of bêta (Estimated delivery October 2023)

- Custom directives (Filters / sorting)
- Automatic documentation with extension possible
- Refactor actions listing to --> Get resource informations (fields exposed / actions / etc ? regroupe all those possibilities)
- Alias for includes / aggregates
-

## Roadmap

Expand Down
16 changes: 4 additions & 12 deletions src/Actions/Action.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Lomkit\Rest\Concerns\Fieldable;
use Lomkit\Rest\Concerns\Makeable;
use Lomkit\Rest\Concerns\Metable;
use Lomkit\Rest\Concerns\Resourcable;
use Lomkit\Rest\Http\Requests\OperateRequest;
use Lomkit\Rest\Http\Requests\RestRequest;
use Lomkit\Rest\Http\Resource;

class Action implements \JsonSerializable
{
use Makeable, Metable, Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
use Makeable, Metable, Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Fieldable, Resourcable;

/**
* The name of the connection the job should be sent to.
Expand Down Expand Up @@ -96,17 +99,6 @@ public function handle(array $fields, \Illuminate\Support\Collection $models)
//
}

/**
* Called in an action failed.
*
* @param \Lomkit\Rest\Http\Requests\RestRequest $request
* @return array
*/
public function fields(\Lomkit\Rest\Http\Requests\RestRequest $request)
{
return [];
}

/**
* Register callbacks on the pending batch.
*
Expand Down
3 changes: 2 additions & 1 deletion src/Actions/Actionable.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public function action(RestRequest $request, string $actionKey): Action {
return collect($this->actions($request))
->sole(function (Action $action) use ($actionKey) {
return $action->uriKey() === $actionKey;
});
})
->resource($this);
}
}
5 changes: 4 additions & 1 deletion src/Actions/DispatchAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ public function forModels(Collection $models)
protected function dispatchSynchronouslyForCollection(Collection $models)
{
return DB::transaction(function () use ($models) {
return $this->action->handle($this->fields, $models);
return $this->action->handle(
collect($this->fields)->mapWithKeys(function ($field) {return [ $field['name'] => $field['value']]; })->toArray(),
$models
);
});
}

Expand Down
30 changes: 30 additions & 0 deletions src/Concerns/Fieldable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Lomkit\Rest\Concerns;

trait Fieldable
{
/**
* The fields.
*
* @param \Lomkit\Rest\Http\Requests\RestRequest $request
* @return array
*/
public function fields(\Lomkit\Rest\Http\Requests\RestRequest $request): array
{
return [];
}

/**
* The fields.
*
* @param \Lomkit\Rest\Http\Requests\RestRequest $request
* @param string $name
* @return array
*/
public function field(\Lomkit\Rest\Http\Requests\RestRequest $request, string $name)
{
return collect($this->fields($request))
->first(function ($value, $fieldName) use ($name) { return $fieldName === $name; });
}
}
27 changes: 27 additions & 0 deletions src/Concerns/Resourcable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Lomkit\Rest\Concerns;

use Lomkit\Rest\Http\Resource;

trait Resourcable
{
/**
* The resource.
*
* @var Resource
*/
public Resource $resource;

/**
* Set the resource.
*
* @param Resource $resource
* @return array
*/
public function resource(Resource $resource) {
return tap($this, function() use ($resource) {
$this->resource = $resource;
});
}
}
11 changes: 10 additions & 1 deletion src/Http/Requests/OperateRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Lomkit\Rest\Relations\MorphedByMany;
use Lomkit\Rest\Relations\MorphMany;
use Lomkit\Rest\Relations\MorphToMany;
use Lomkit\Rest\Rules\ActionField;
use Lomkit\Rest\Rules\CustomRulable;
use Lomkit\Rest\Rules\Includable;
use Lomkit\Rest\Rules\RequiredRelation;
Expand All @@ -42,8 +43,16 @@ public function operateRules(Resource $resource)
return array_merge(
app(SearchRequest::class)->searchRules($resource, 'search'),
[
'fields.*.name' => [
Rule::in(array_keys($operatedAction->fields($this)))
],
'fields' => [
'array:'.implode(',', array_keys($operatedAction->fields($this)))
'sometimes',
'array'
],
'fields.*' => [
ActionField::make()
->action($operatedAction)
]
]
);
Expand Down
16 changes: 2 additions & 14 deletions src/Http/Requests/RestRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,11 @@
namespace Lomkit\Rest\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Lomkit\Rest\Concerns\Resourcable;
use Lomkit\Rest\Http\Requests\Traits\InteractsWithRules;
use Lomkit\Rest\Http\Resource;

class RestRequest extends FormRequest
{
use InteractsWithRules;

/**
* The resource the request is linked to.
*
* @var Resource
*/
public Resource $resource;

public function resource(Resource $resource) {
return tap($this, function() use ($resource) {
$this->resource = $resource;
});
}
use InteractsWithRules, Resourcable;
}
27 changes: 27 additions & 0 deletions src/Http/Requests/SearchRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Lomkit\Rest\Rules\AggregateField;
use Lomkit\Rest\Rules\AggregateFilterable;
use Lomkit\Rest\Rules\Includable;
use Lomkit\Rest\Rules\Instruction;

class SearchRequest extends RestRequest
{
Expand All @@ -36,6 +37,8 @@ public function searchRules(Resource $resource, $prefix = '', $isRootSearchRules
$this->selectsRules($resource, $prefix.'selects'),
[$prefix.'aggregates' => ['sometimes', 'array']],
$this->aggregatesRules($resource, $prefix.'aggregates'),
[$prefix.'instructions' => ['sometimes', 'array']],
$this->instructionsRules($resource, $prefix.'instructions'),
[
'limit' => ['sometimes', 'integer', Rule::in($resource->exposedLimits($this))],
'page' => ['sometimes', 'integer']
Expand Down Expand Up @@ -96,6 +99,30 @@ protected function scopesRules(Resource $resource, string $prefix) {
return $rules;
}

protected function instructionsRules(Resource $resource, string $prefix) {
$rules = [
$prefix.'.*.name' => [
Rule::in(
collect($resource->instructions($this))
->map(function ($instruction) { return $instruction->uriKey(); })
->toArray()
),
'required',
'string'
],
$prefix.'.*.fields' => [
'sometimes',
'array'
],
$prefix.'.*' => [
Instruction::make()
->resource($resource)
]
];

return $rules;
}

protected function sortsRules(Resource $resource, string $prefix) {
$rules = [
$prefix.'.*.field' => [
Expand Down
4 changes: 3 additions & 1 deletion src/Http/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Lomkit\Rest\Concerns\Resource\Relationable;
use Lomkit\Rest\Concerns\Resource\Rulable;
use Lomkit\Rest\Http\Requests\RestRequest;
use Lomkit\Rest\Instructions\Instructionable;

class Resource
{
Expand All @@ -22,7 +23,8 @@ class Resource
Rulable,
ConfiguresRestParameters,
Authorizable,
Actionable;
Actionable,
Instructionable;

/**
* The model the entry corresponds to.
Expand Down
2 changes: 1 addition & 1 deletion src/Http/Routing/ResourceRegistrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ protected function addResourceActions($name, $base, $controller, $options)
}

/**
* Add the actions method for a resourceful route.
* Add the operate method for a resourceful route.
*
* @param string $name
* @param string $base
Expand Down
72 changes: 72 additions & 0 deletions src/Instructions/Instruction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace Lomkit\Rest\Instructions;

use Illuminate\Support\Str;
use Lomkit\Rest\Concerns\Fieldable;
use Lomkit\Rest\Concerns\Makeable;
use Lomkit\Rest\Concerns\Metable;
use Lomkit\Rest\Concerns\Resourcable;
use Lomkit\Rest\Http\Requests\RestRequest;
use Lomkit\Rest\Query\Builder;

class Instruction
{
use Makeable, Metable, Fieldable, Resourcable;

/**
* The displayable name of the instruction.
*
* @var string
*/
public $name;

/**
* Get the name of the instruction.
*
* @return string
*/
public function name()
{
return $this->name ?: Str::of(class_basename(get_class($this)))->beforeLast('Instruction')->snake(' ')->title();
}

/**
* Get the URI key for the instruction.
*
* @return string
*/
public function uriKey()
{
return Str::slug($this->name(), '-', null);
}

/**
* Prepare the action for JSON serialization.
*
* @return array<string, mixed>
*/
public function jsonSerialize(): array
{
$request = app()->make(RestRequest::class);

return [
'name' => $this->name(),
'uriKey' => $this->uriKey(),
'fields' => $this->fields($request),
'meta' => $this->meta()
];
}

/**
* Perform the instruction on the given query.
*
* @param array $fields
* @param \Illuminate\Database\Eloquent\Builder $query
* @return void
*/
public function handle(array $fields, \Illuminate\Database\Eloquent\Builder $query)
{
// ...
}
}
39 changes: 39 additions & 0 deletions src/Instructions/Instructionable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Lomkit\Rest\Instructions;

use Lomkit\Rest\Http\Requests\RestRequest;
use Lomkit\Rest\Instructions\Instruction;

trait Instructionable
{
/**
* The instructions that should be linked
* @param RestRequest $request
* @return array
*/
public function instructions(RestRequest $request): array {
return [];
}

public function instructionExists(RestRequest $request, string $instructionKey): bool {
return collect($this->instructions($request))
->contains(function (Instruction $instruction) use ($instructionKey) {
return $instruction->uriKey() === $instructionKey;
});
}

public function instruction(RestRequest $request, string $instructionKey) {
$instruction = collect($this->instructions($request))
->first(function (Instruction $instruction) use ($instructionKey) {
return $instruction->uriKey() === $instructionKey;
});

if (!is_null($instruction)) {
$instruction
->resource($this);
}

return $instruction;
}
}
Loading

0 comments on commit 82d3a3d

Please sign in to comment.