Skip to content

Commit

Permalink
✨ resource detail
Browse files Browse the repository at this point in the history
  • Loading branch information
GautierDele committed Aug 17, 2023
1 parent 5c84134 commit d9b3d0d
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/Actions/Action.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class Action implements \JsonSerializable
*/
public function name()
{
return $this->name ?: Str::of(class_basename(get_class($this)))->beforeLast('Action')->snake(' ')->title();
return $this->name ?: Str::of(class_basename(get_class($this)))->beforeLast('Action')->snake(' ')->title()->toString();
}

/**
Expand Down
20 changes: 11 additions & 9 deletions src/Concerns/PerformsRestOperations.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Lomkit\Rest\Contracts\QueryBuilder;
use Lomkit\Rest\Http\Requests\ActionsRequest;
use Lomkit\Rest\Http\Requests\DestroyRequest;
use Lomkit\Rest\Http\Requests\DetailRequest;
use Lomkit\Rest\Http\Requests\ForceDestroyRequest;
use Lomkit\Rest\Http\Requests\OperateRequest;
use Lomkit\Rest\Http\Requests\RestoreRequest;
Expand All @@ -19,6 +20,16 @@

trait PerformsRestOperations
{
public function detail(DetailRequest $request) {
$request->resource($resource = static::newResource());

$resource->authorizeTo('viewAny', $resource::$model);

return [
'data' => $resource->jsonSerialize()
];
}

public function search(SearchRequest $request) {
$request->resource($resource = static::newResource());

Expand Down Expand Up @@ -48,15 +59,6 @@ public function mutate(MutateRequest $request) {
return $operations;
}

public function actions(ActionsRequest $request) {
$request->resource($resource = static::newResource());

return response([
'data' =>
collect($resource->actions($request))->each->jsonSerialize()
]);
}

public function operate(OperateRequest $request, $action) {
$request->resource($resource = static::newResource());

Expand Down
31 changes: 31 additions & 0 deletions src/Http/Requests/DetailRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Lomkit\Rest\Http\Requests;

use Closure;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Arr;
use Illuminate\Support\Fluent;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Lomkit\Rest\Actions\Action;
use Lomkit\Rest\Contracts\QueryBuilder;
use Lomkit\Rest\Http\Controllers\Controller;
use Lomkit\Rest\Http\Resource;
use Lomkit\Rest\Relations\BelongsTo;
use Lomkit\Rest\Relations\BelongsToMany;
use Lomkit\Rest\Relations\HasMany;
use Lomkit\Rest\Relations\HasManyThrough;
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;
use Symfony\Component\HttpKernel\Exception\HttpException;

class DetailRequest extends RestRequest
{

}
21 changes: 20 additions & 1 deletion src/Http/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use Lomkit\Rest\Http\Requests\RestRequest;
use Lomkit\Rest\Instructions\Instructionable;

class Resource
class Resource implements \JsonSerializable
{
use PerformsQueries,
PerformsModelOperations,
Expand Down Expand Up @@ -79,4 +79,23 @@ public function isAutomaticGatingEnabled() : bool {
public function isAuthorizingEnabled() : bool {
return config('rest.authorizations.enabled');
}

public function jsonSerialize(): mixed
{
$request = app(RestRequest::class);

return [
'actions' => collect($this->actions($request))->map->jsonSerialize()->toArray(),
'instructions' => collect($this->instructions($request))->map->jsonSerialize()->toArray(),
'fields' => $this->exposedFields($request),
'limits' => $this->exposedLimits($request),
'scopes' => $this->exposedScopes($request),
'relations' => collect($this->relations($request))->map->jsonSerialize()->toArray(),
'rules' => [
'all' => $this->rules($request),
'create' => $this->createRules($request),
'update' => $this->updateRules($request)
]
];
}
}
30 changes: 15 additions & 15 deletions src/Http/Routing/ResourceRegistrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ResourceRegistrar extends BaseResourceRegistrar
*
* @var string[]
*/
protected $resourceDefaults = ['search', 'mutate', 'actions', 'operate', 'destroy', 'restore', 'forceDelete'];
protected $resourceDefaults = ['detail', 'search', 'mutate', 'operate', 'destroy', 'restore', 'forceDelete'];

/**
* The verbs used in the resource URIs.
Expand All @@ -30,63 +30,63 @@ class ResourceRegistrar extends BaseResourceRegistrar
];

/**
* Add the search method for a resourceful route.
* Add the detail method for a resourceful route.
*
* @param string $name
* @param string $base
* @param string $controller
* @param array $options
* @return \Illuminate\Routing\Route
*/
protected function addResourceSearch($name, $base, $controller, $options)
protected function addResourceDetail($name, $base, $controller, $options)
{
$uri = $this->getResourceUri($name).'/'.static::$verbs['search'];
$uri = $this->getResourceUri($name);

unset($options['missing']);

$action = $this->getResourceAction($name, $controller, 'search', $options);
$action = $this->getResourceAction($name, $controller, 'detail', $options);

return $this->router->post($uri, $action);
return $this->router->get($uri, $action);
}

/**
* Add the mutate method for a resourceful route.
* Add the search method for a resourceful route.
*
* @param string $name
* @param string $base
* @param string $controller
* @param array $options
* @return \Illuminate\Routing\Route
*/
protected function addResourceMutate($name, $base, $controller, $options)
protected function addResourceSearch($name, $base, $controller, $options)
{
$uri = $this->getResourceUri($name).'/'.static::$verbs['mutate'];
$uri = $this->getResourceUri($name).'/'.static::$verbs['search'];

unset($options['missing']);

$action = $this->getResourceAction($name, $controller, 'mutate', $options);
$action = $this->getResourceAction($name, $controller, 'search', $options);

return $this->router->post($uri, $action);
}

/**
* Add the actions method for a resourceful route.
* Add the mutate method for a resourceful route.
*
* @param string $name
* @param string $base
* @param string $controller
* @param array $options
* @return \Illuminate\Routing\Route
*/
protected function addResourceActions($name, $base, $controller, $options)
protected function addResourceMutate($name, $base, $controller, $options)
{
$uri = $this->getResourceUri($name).'/'.static::$verbs['actions'];
$uri = $this->getResourceUri($name).'/'.static::$verbs['mutate'];

unset($options['missing']);

$action = $this->getResourceAction($name, $controller, 'actions', $options);
$action = $this->getResourceAction($name, $controller, 'mutate', $options);

return $this->router->get($uri, $action);
return $this->router->post($uri, $action);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Instructions/Instruction.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Instruction
*/
public function name()
{
return $this->name ?: Str::of(class_basename(get_class($this)))->beforeLast('Instruction')->snake(' ')->title();
return $this->name ?: Str::of(class_basename(get_class($this)))->beforeLast('Instruction')->snake(' ')->title()->toString();
}

/**
Expand Down
33 changes: 32 additions & 1 deletion src/Relations/Relation.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,19 @@
use Lomkit\Rest\Relations\Traits\Mutates;
use Lomkit\Rest\Rules\RequiredRelation;

class Relation
class Relation implements \JsonSerializable
{
use Makeable, Mutates, Constrained;
public string $relation;
protected array $types;

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

protected Resource $fromResource;

public function __construct($relation, $type)
Expand All @@ -28,6 +35,16 @@ public function __construct($relation, $type)
$this->types = [$type];
}

/**
* Get the name of the relation.
*
* @return string
*/
public function name()
{
return $this->name ?: (new \ReflectionClass($this))->getShortName();
}

public function filter(Builder $query, $relation, $operator, $value, $boolean = 'and', Closure $callback = null)
{
return $query->has(Str::beforeLast(relation_without_pivot($relation), '.'), '>=', 1, $boolean, function (Builder $query) use ($value, $operator, $relation, $callback) {
Expand Down Expand Up @@ -90,4 +107,18 @@ public function rules(Resource $resource, string $prefix) {

return $rules;
}

public function jsonSerialize(): mixed
{
$request = app(RestRequest::class);

return [
'resources' => $this->types,
'relation' => $this->relation,
'constraints' => [
'requiredOnCreation' => $this->isRequiredOnCreation($request)
],
'name' => $this->name()
];
}
}
14 changes: 0 additions & 14 deletions tests/Feature/Controllers/ActionsOperationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,6 @@

class ActionsOperationsTest extends TestCase
{
public function test_getting_actions(): void
{
ModelFactory::new()->count(2)->create();

$response = $this->get(
'/api/models/actions',
['Accept' => 'application/json']
);

$response->assertExactJson(
['data' => collect((new ModelResource)->actions(app(RestRequest::class)))->map->jsonSerialize()->toArray()]
);
}

public function test_operate_action(): void
{
ModelFactory::new()->count(2)->create();
Expand Down
45 changes: 45 additions & 0 deletions tests/Feature/Controllers/DetailOperationsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace Lomkit\Rest\Tests\Feature\Controllers;

use Illuminate\Bus\PendingBatch;
use Illuminate\Queue\Queue;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Gate;
use Lomkit\Rest\Actions\CallRestApiAction;
use Lomkit\Rest\Http\Requests\RestRequest;
use Lomkit\Rest\Tests\Feature\TestCase;
use Lomkit\Rest\Tests\Support\Database\Factories\BelongsToManyRelationFactory;
use Lomkit\Rest\Tests\Support\Database\Factories\BelongsToRelationFactory;
use Lomkit\Rest\Tests\Support\Database\Factories\HasManyRelationFactory;
use Lomkit\Rest\Tests\Support\Database\Factories\HasOneRelationFactory;
use Lomkit\Rest\Tests\Support\Database\Factories\ModelFactory;
use Lomkit\Rest\Tests\Support\Models\BelongsToManyRelation;
use Lomkit\Rest\Tests\Support\Models\BelongsToRelation;
use Lomkit\Rest\Tests\Support\Models\Model;
use Lomkit\Rest\Tests\Support\Policies\GreenPolicy;
use Lomkit\Rest\Tests\Support\Policies\RedPolicy;
use Lomkit\Rest\Tests\Support\Rest\Resources\BelongsToManyResource;
use Lomkit\Rest\Tests\Support\Rest\Resources\BelongsToResource;
use Lomkit\Rest\Tests\Support\Rest\Resources\HasManyResource;
use Lomkit\Rest\Tests\Support\Rest\Resources\HasOneResource;
use Lomkit\Rest\Tests\Support\Rest\Resources\ModelResource;

class DetailOperationsTest extends TestCase
{
public function test_operate_action(): void
{
ModelFactory::new()->count(2)->create();

Gate::policy(Model::class, GreenPolicy::class);

$response = $this->get(
'/api/models',
['Accept' => 'application/json']
);

$response->assertJson([
'data' => (new ModelResource())->jsonSerialize()
]);
}
}

0 comments on commit d9b3d0d

Please sign in to comment.