Skip to content

Commit d9b3d0d

Browse files
committed
✨ resource detail
1 parent 5c84134 commit d9b3d0d

File tree

9 files changed

+156
-42
lines changed

9 files changed

+156
-42
lines changed

src/Actions/Action.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class Action implements \JsonSerializable
5757
*/
5858
public function name()
5959
{
60-
return $this->name ?: Str::of(class_basename(get_class($this)))->beforeLast('Action')->snake(' ')->title();
60+
return $this->name ?: Str::of(class_basename(get_class($this)))->beforeLast('Action')->snake(' ')->title()->toString();
6161
}
6262

6363
/**

src/Concerns/PerformsRestOperations.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Lomkit\Rest\Contracts\QueryBuilder;
1111
use Lomkit\Rest\Http\Requests\ActionsRequest;
1212
use Lomkit\Rest\Http\Requests\DestroyRequest;
13+
use Lomkit\Rest\Http\Requests\DetailRequest;
1314
use Lomkit\Rest\Http\Requests\ForceDestroyRequest;
1415
use Lomkit\Rest\Http\Requests\OperateRequest;
1516
use Lomkit\Rest\Http\Requests\RestoreRequest;
@@ -19,6 +20,16 @@
1920

2021
trait PerformsRestOperations
2122
{
23+
public function detail(DetailRequest $request) {
24+
$request->resource($resource = static::newResource());
25+
26+
$resource->authorizeTo('viewAny', $resource::$model);
27+
28+
return [
29+
'data' => $resource->jsonSerialize()
30+
];
31+
}
32+
2233
public function search(SearchRequest $request) {
2334
$request->resource($resource = static::newResource());
2435

@@ -48,15 +59,6 @@ public function mutate(MutateRequest $request) {
4859
return $operations;
4960
}
5061

51-
public function actions(ActionsRequest $request) {
52-
$request->resource($resource = static::newResource());
53-
54-
return response([
55-
'data' =>
56-
collect($resource->actions($request))->each->jsonSerialize()
57-
]);
58-
}
59-
6062
public function operate(OperateRequest $request, $action) {
6163
$request->resource($resource = static::newResource());
6264

src/Http/Requests/DetailRequest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Lomkit\Rest\Http\Requests;
4+
5+
use Closure;
6+
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
7+
use Illuminate\Support\Arr;
8+
use Illuminate\Support\Fluent;
9+
use Illuminate\Support\Str;
10+
use Illuminate\Validation\Rule;
11+
use Lomkit\Rest\Actions\Action;
12+
use Lomkit\Rest\Contracts\QueryBuilder;
13+
use Lomkit\Rest\Http\Controllers\Controller;
14+
use Lomkit\Rest\Http\Resource;
15+
use Lomkit\Rest\Relations\BelongsTo;
16+
use Lomkit\Rest\Relations\BelongsToMany;
17+
use Lomkit\Rest\Relations\HasMany;
18+
use Lomkit\Rest\Relations\HasManyThrough;
19+
use Lomkit\Rest\Relations\MorphedByMany;
20+
use Lomkit\Rest\Relations\MorphMany;
21+
use Lomkit\Rest\Relations\MorphToMany;
22+
use Lomkit\Rest\Rules\ActionField;
23+
use Lomkit\Rest\Rules\CustomRulable;
24+
use Lomkit\Rest\Rules\Includable;
25+
use Lomkit\Rest\Rules\RequiredRelation;
26+
use Symfony\Component\HttpKernel\Exception\HttpException;
27+
28+
class DetailRequest extends RestRequest
29+
{
30+
31+
}

src/Http/Resource.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use Lomkit\Rest\Http\Requests\RestRequest;
1515
use Lomkit\Rest\Instructions\Instructionable;
1616

17-
class Resource
17+
class Resource implements \JsonSerializable
1818
{
1919
use PerformsQueries,
2020
PerformsModelOperations,
@@ -79,4 +79,23 @@ public function isAutomaticGatingEnabled() : bool {
7979
public function isAuthorizingEnabled() : bool {
8080
return config('rest.authorizations.enabled');
8181
}
82+
83+
public function jsonSerialize(): mixed
84+
{
85+
$request = app(RestRequest::class);
86+
87+
return [
88+
'actions' => collect($this->actions($request))->map->jsonSerialize()->toArray(),
89+
'instructions' => collect($this->instructions($request))->map->jsonSerialize()->toArray(),
90+
'fields' => $this->exposedFields($request),
91+
'limits' => $this->exposedLimits($request),
92+
'scopes' => $this->exposedScopes($request),
93+
'relations' => collect($this->relations($request))->map->jsonSerialize()->toArray(),
94+
'rules' => [
95+
'all' => $this->rules($request),
96+
'create' => $this->createRules($request),
97+
'update' => $this->updateRules($request)
98+
]
99+
];
100+
}
82101
}

src/Http/Routing/ResourceRegistrar.php

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class ResourceRegistrar extends BaseResourceRegistrar
1414
*
1515
* @var string[]
1616
*/
17-
protected $resourceDefaults = ['search', 'mutate', 'actions', 'operate', 'destroy', 'restore', 'forceDelete'];
17+
protected $resourceDefaults = ['detail', 'search', 'mutate', 'operate', 'destroy', 'restore', 'forceDelete'];
1818

1919
/**
2020
* The verbs used in the resource URIs.
@@ -30,63 +30,63 @@ class ResourceRegistrar extends BaseResourceRegistrar
3030
];
3131

3232
/**
33-
* Add the search method for a resourceful route.
33+
* Add the detail method for a resourceful route.
3434
*
3535
* @param string $name
3636
* @param string $base
3737
* @param string $controller
3838
* @param array $options
3939
* @return \Illuminate\Routing\Route
4040
*/
41-
protected function addResourceSearch($name, $base, $controller, $options)
41+
protected function addResourceDetail($name, $base, $controller, $options)
4242
{
43-
$uri = $this->getResourceUri($name).'/'.static::$verbs['search'];
43+
$uri = $this->getResourceUri($name);
4444

4545
unset($options['missing']);
4646

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

49-
return $this->router->post($uri, $action);
49+
return $this->router->get($uri, $action);
5050
}
5151

5252
/**
53-
* Add the mutate method for a resourceful route.
53+
* Add the search method for a resourceful route.
5454
*
5555
* @param string $name
5656
* @param string $base
5757
* @param string $controller
5858
* @param array $options
5959
* @return \Illuminate\Routing\Route
6060
*/
61-
protected function addResourceMutate($name, $base, $controller, $options)
61+
protected function addResourceSearch($name, $base, $controller, $options)
6262
{
63-
$uri = $this->getResourceUri($name).'/'.static::$verbs['mutate'];
63+
$uri = $this->getResourceUri($name).'/'.static::$verbs['search'];
6464

6565
unset($options['missing']);
6666

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

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

7272
/**
73-
* Add the actions method for a resourceful route.
73+
* Add the mutate method for a resourceful route.
7474
*
7575
* @param string $name
7676
* @param string $base
7777
* @param string $controller
7878
* @param array $options
7979
* @return \Illuminate\Routing\Route
8080
*/
81-
protected function addResourceActions($name, $base, $controller, $options)
81+
protected function addResourceMutate($name, $base, $controller, $options)
8282
{
83-
$uri = $this->getResourceUri($name).'/'.static::$verbs['actions'];
83+
$uri = $this->getResourceUri($name).'/'.static::$verbs['mutate'];
8484

8585
unset($options['missing']);
8686

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

89-
return $this->router->get($uri, $action);
89+
return $this->router->post($uri, $action);
9090
}
9191

9292
/**

src/Instructions/Instruction.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class Instruction
2828
*/
2929
public function name()
3030
{
31-
return $this->name ?: Str::of(class_basename(get_class($this)))->beforeLast('Instruction')->snake(' ')->title();
31+
return $this->name ?: Str::of(class_basename(get_class($this)))->beforeLast('Instruction')->snake(' ')->title()->toString();
3232
}
3333

3434
/**

src/Relations/Relation.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,19 @@
1414
use Lomkit\Rest\Relations\Traits\Mutates;
1515
use Lomkit\Rest\Rules\RequiredRelation;
1616

17-
class Relation
17+
class Relation implements \JsonSerializable
1818
{
1919
use Makeable, Mutates, Constrained;
2020
public string $relation;
2121
protected array $types;
2222

23+
/**
24+
* The displayable name of the relation.
25+
*
26+
* @var string
27+
*/
28+
public $name;
29+
2330
protected Resource $fromResource;
2431

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

38+
/**
39+
* Get the name of the relation.
40+
*
41+
* @return string
42+
*/
43+
public function name()
44+
{
45+
return $this->name ?: (new \ReflectionClass($this))->getShortName();
46+
}
47+
3148
public function filter(Builder $query, $relation, $operator, $value, $boolean = 'and', Closure $callback = null)
3249
{
3350
return $query->has(Str::beforeLast(relation_without_pivot($relation), '.'), '>=', 1, $boolean, function (Builder $query) use ($value, $operator, $relation, $callback) {
@@ -90,4 +107,18 @@ public function rules(Resource $resource, string $prefix) {
90107

91108
return $rules;
92109
}
110+
111+
public function jsonSerialize(): mixed
112+
{
113+
$request = app(RestRequest::class);
114+
115+
return [
116+
'resources' => $this->types,
117+
'relation' => $this->relation,
118+
'constraints' => [
119+
'requiredOnCreation' => $this->isRequiredOnCreation($request)
120+
],
121+
'name' => $this->name()
122+
];
123+
}
93124
}

tests/Feature/Controllers/ActionsOperationsTest.php

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,6 @@
2727

2828
class ActionsOperationsTest extends TestCase
2929
{
30-
public function test_getting_actions(): void
31-
{
32-
ModelFactory::new()->count(2)->create();
33-
34-
$response = $this->get(
35-
'/api/models/actions',
36-
['Accept' => 'application/json']
37-
);
38-
39-
$response->assertExactJson(
40-
['data' => collect((new ModelResource)->actions(app(RestRequest::class)))->map->jsonSerialize()->toArray()]
41-
);
42-
}
43-
4430
public function test_operate_action(): void
4531
{
4632
ModelFactory::new()->count(2)->create();
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Lomkit\Rest\Tests\Feature\Controllers;
4+
5+
use Illuminate\Bus\PendingBatch;
6+
use Illuminate\Queue\Queue;
7+
use Illuminate\Support\Facades\Bus;
8+
use Illuminate\Support\Facades\Gate;
9+
use Lomkit\Rest\Actions\CallRestApiAction;
10+
use Lomkit\Rest\Http\Requests\RestRequest;
11+
use Lomkit\Rest\Tests\Feature\TestCase;
12+
use Lomkit\Rest\Tests\Support\Database\Factories\BelongsToManyRelationFactory;
13+
use Lomkit\Rest\Tests\Support\Database\Factories\BelongsToRelationFactory;
14+
use Lomkit\Rest\Tests\Support\Database\Factories\HasManyRelationFactory;
15+
use Lomkit\Rest\Tests\Support\Database\Factories\HasOneRelationFactory;
16+
use Lomkit\Rest\Tests\Support\Database\Factories\ModelFactory;
17+
use Lomkit\Rest\Tests\Support\Models\BelongsToManyRelation;
18+
use Lomkit\Rest\Tests\Support\Models\BelongsToRelation;
19+
use Lomkit\Rest\Tests\Support\Models\Model;
20+
use Lomkit\Rest\Tests\Support\Policies\GreenPolicy;
21+
use Lomkit\Rest\Tests\Support\Policies\RedPolicy;
22+
use Lomkit\Rest\Tests\Support\Rest\Resources\BelongsToManyResource;
23+
use Lomkit\Rest\Tests\Support\Rest\Resources\BelongsToResource;
24+
use Lomkit\Rest\Tests\Support\Rest\Resources\HasManyResource;
25+
use Lomkit\Rest\Tests\Support\Rest\Resources\HasOneResource;
26+
use Lomkit\Rest\Tests\Support\Rest\Resources\ModelResource;
27+
28+
class DetailOperationsTest extends TestCase
29+
{
30+
public function test_operate_action(): void
31+
{
32+
ModelFactory::new()->count(2)->create();
33+
34+
Gate::policy(Model::class, GreenPolicy::class);
35+
36+
$response = $this->get(
37+
'/api/models',
38+
['Accept' => 'application/json']
39+
);
40+
41+
$response->assertJson([
42+
'data' => (new ModelResource())->jsonSerialize()
43+
]);
44+
}
45+
}

0 commit comments

Comments
 (0)