Skip to content

Commit ea1763f

Browse files
authored
Action logs. (#341)
* Apply fixes from StyleCI (#342) * Action logs docs. * Apply fixes from StyleCI (#343)
1 parent 2f9026f commit ea1763f

File tree

7 files changed

+150
-14
lines changed

7 files changed

+150
-14
lines changed

docs/docs/4.0/actions/actions.md

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,23 @@ You can apply any filter or eager loadings as for an usual request:
169169
POST: api/api/restify/posts/actions?action=publish-posts-action&id=1&filters=
170170
```
171171

172-
This will apply the match for the `id = 1` and `filtetr` along with the match for the `repositories` payload you're sending.
172+
This will apply the match for the `id = 1` and `filter` along with the match for the `repositories` payload you're sending.
173+
174+
### Modify query
175+
176+
Similar with the way we can modify the query applied to the repository, we can do the same by adding the `indexQuery` method on the action:
177+
178+
```php
179+
class PublishPostAction extends Action
180+
{
181+
public static function indexQuery(RestifyRequest $request, $query)
182+
{
183+
$query->whereNotNull('published_at');
184+
}
185+
186+
//...
187+
}
188+
```
173189

174190
## All
175191

@@ -179,8 +195,6 @@ Sometimes you may need to apply an action for all models. For this you can send:
179195
repositories: 'all'
180196
```
181197

182-
## Chunk
183-
184198
Under the hood Restify will take by 200 chunks entries from the database and the handle method for these in a DB transaction. You are free to modify this default number of chunks:
185199

186200
```php
@@ -200,7 +214,6 @@ public function actions(RestifyRequest $request)
200214
}
201215
```
202216

203-
204217
And available actions only for a specific repository id could be listed like:
205218

206219
```http request
@@ -277,3 +290,59 @@ class DisableProfileAction extends Action
277290
//...
278291
}
279292
```
293+
294+
## Action Log
295+
296+
It is often useful to view a log of the actions that have been run against a model, or seeing when the model was updated, deleted or created (and by whom). Thankfully, Restify makes it a breeze to add an action log to a model by attaching the `Binaryk\LaravelRestify\Models\Concerns\HasActionLogs` trait to the repository's corresponding Eloquent model.
297+
298+
Having `HasActionLogs` trait attached to your model, all of the actions and CRUD operations will be logged into the database into the `action_logs` table.
299+
300+
You can display them by attaching to the repository related for example:
301+
302+
```php
303+
// PostRepository.php
304+
use Binaryk\LaravelRestify\Fields\MorphToMany;
305+
use Binaryk\LaravelRestify\Repositories\ActionLogRepository;
306+
307+
public static function related(): array
308+
{
309+
return [
310+
'logs' => MorphToMany::make('actionLogs', 'actionLogs', ActionLogRepository::class),
311+
];
312+
}
313+
```
314+
315+
So now you can call the posts with logs `api/restify/posts/1?related=logs`, and it will return you the list of actions performed for posts:
316+
317+
```json
318+
[
319+
{
320+
"id": "1",
321+
"type": "action_logs",
322+
"attributes": {
323+
"batch_id": "048686bb-cd22-41a7-a6db-3eba29678d74",
324+
"user_id": "1",
325+
"name": "Stored",
326+
"actionable_type": "App\\Models\\Post",
327+
"actionable_id": "1",
328+
"target_type": "App\\Models\\Post",
329+
"target_id": "1",
330+
"model_type": "App\\Models\\Post",
331+
"model_id": "1",
332+
"fields": "",
333+
"status": "finished",
334+
"original": "",
335+
"changes": [],
336+
"exception": ""
337+
},
338+
"meta": {
339+
"authorizedToShow": true,
340+
"authorizedToStore": true,
341+
"authorizedToUpdate": true,
342+
"authorizedToDelete": true
343+
}
344+
}
345+
]
346+
```
347+
348+
Definitely you can use your own `ActionLogRepository` to represent the data returned, maybe you prefer to represent the user details or something else.

src/Repositories/ActionLogRepository.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,20 @@ class ActionLogRepository extends Repository
1212
public function fields(RestifyRequest $request)
1313
{
1414
return [
15-
field('actionable_type'),
16-
17-
field('actionable_id'),
15+
field('batch_id')->readonly(),
16+
field('user_id')->readonly(),
17+
field('name')->readonly(),
18+
field('actionable_type')->readonly(),
19+
field('actionable_id')->readonly(),
20+
field('target_type')->readonly(),
21+
field('target_id')->readonly(),
22+
field('model_type')->readonly(),
23+
field('model_id')->readonly(),
24+
field('fields')->readonly(),
25+
field('status')->readonly(),
26+
field('original')->readonly(),
27+
field('changes')->readonly(),
28+
field('exception')->readonly(),
1829
];
1930
}
2031
}

src/Repositories/Repository.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace Binaryk\LaravelRestify\Repositories;
44

5-
use Binaryk\LaravelRestify\Contracts\ActionLogable;
65
use Binaryk\LaravelRestify\Contracts\RestifySearchable;
76
use Binaryk\LaravelRestify\Controllers\RestResponse;
87
use Binaryk\LaravelRestify\Eager\Related;
@@ -15,6 +14,7 @@
1514
use Binaryk\LaravelRestify\Filter;
1615
use Binaryk\LaravelRestify\Http\Requests\RepositoryStoreBulkRequest;
1716
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
17+
use Binaryk\LaravelRestify\Models\Concerns\HasActionLogs;
1818
use Binaryk\LaravelRestify\Models\CreationAware;
1919
use Binaryk\LaravelRestify\Repositories\Concerns\InteractsWithAttachers;
2020
use Binaryk\LaravelRestify\Repositories\Concerns\Mockable;
@@ -705,7 +705,7 @@ public function store(RestifyRequest $request)
705705
}
706706
}
707707

708-
if ($this->resource instanceof ActionLogable) {
708+
if (in_array(HasActionLogs::class, class_uses_recursive($this->resource))) {
709709
Restify::actionLog()
710710
->forRepositoryStored($this->resource, $request->user(), $dirty)
711711
->save();
@@ -765,7 +765,7 @@ public function update(RestifyRequest $request, $repositoryId)
765765

766766
static::fillFields($request, $this->resource, $fields);
767767

768-
if ($this->resource instanceof ActionLogable) {
768+
if (in_array(HasActionLogs::class, class_uses_recursive($this->resource))) {
769769
Restify::actionLog()
770770
->forRepositoryUpdated($this->resource, $request->user())
771771
->save();
@@ -842,7 +842,7 @@ public function detach(RestifyRequest $request, $repositoryId, Collection $pivot
842842
public function destroy(RestifyRequest $request, $repositoryId)
843843
{
844844
$status = DB::transaction(function () use ($request) {
845-
if ($this->resource instanceof ActionLogable) {
845+
if (in_array(HasActionLogs::class, class_uses_recursive($this->resource))) {
846846
Restify::actionLog()
847847
->forRepositoryDestroy($this->resource, $request->user())
848848
->save();

tests/Controllers/RepositoryIndexControllerTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public function test_using_custom_related_casts()
120120
]);
121121
}
122122

123-
public function test_repository_with_deep_relations()
123+
public function test_repository_with_nested_relations()
124124
{
125125
CompanyRepository::partialMock()
126126
->expects('related')
@@ -139,6 +139,7 @@ public function test_repository_with_deep_relations()
139139
});
140140

141141
$response = $this->getJson(CompanyRepository::uriKey().'?related=users.posts')
142+
->dump()
142143
->assertOk();
143144

144145
$this->assertCount(1, $response->json('data.0.relationships.users'));

tests/Fixtures/Post/Post.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22

33
namespace Binaryk\LaravelRestify\Tests\Fixtures\Post;
44

5-
use Binaryk\LaravelRestify\Contracts\ActionLogable;
65
use Binaryk\LaravelRestify\Contracts\RestifySearchable;
76
use Binaryk\LaravelRestify\Models\Concerns\HasActionLogs;
87
use Binaryk\LaravelRestify\Tests\Fixtures\User\User;
98
use Binaryk\LaravelRestify\Traits\InteractWithSearch;
109
use Illuminate\Database\Eloquent\Model;
1110

12-
class Post extends Model implements RestifySearchable, ActionLogable
11+
class Post extends Model implements RestifySearchable
1312
{
1413
use InteractWithSearch, HasActionLogs;
1514

tests/Fixtures/Post/PublishPostAction.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@
44

55
use Binaryk\LaravelRestify\Actions\Action;
66
use Binaryk\LaravelRestify\Http\Requests\ActionRequest;
7+
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
78
use Illuminate\Http\JsonResponse;
89
use Illuminate\Support\Collection;
910

1011
class PublishPostAction extends Action
1112
{
1213
public static $applied = [];
1314

15+
public static function indexQuery(RestifyRequest $request, $query)
16+
{
17+
$query->whereNotNull('published_at');
18+
}
19+
1420
public function handle(ActionRequest $request, Collection $models): JsonResponse
1521
{
1622
static::$applied[] = $models;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace Binaryk\LaravelRestify\Tests\Repositories;
4+
5+
use Binaryk\LaravelRestify\Models\ActionLog;
6+
use Binaryk\LaravelRestify\Repositories\ActionLogRepository;
7+
use Binaryk\LaravelRestify\Restify;
8+
use Binaryk\LaravelRestify\Tests\Fixtures\User\User;
9+
use Binaryk\LaravelRestify\Tests\IntegrationTest;
10+
11+
class ActionLogRepositoryTest extends IntegrationTest
12+
{
13+
protected function setUp(): void
14+
{
15+
parent::setUp();
16+
17+
Restify::repositories([
18+
ActionLogRepository::class,
19+
]);
20+
}
21+
22+
public function test_can_list_action_logs()
23+
{
24+
$this->authenticate();
25+
26+
$log = ActionLog::forRepositoryStored(
27+
factory(User::class)->create(),
28+
$this->authenticatedAs
29+
);
30+
31+
$log->save();
32+
33+
$this->getJson(ActionLogRepository::uriKey())
34+
->assertOk()
35+
->assertJsonStructure([
36+
'data' => [
37+
[
38+
'id',
39+
'type',
40+
'attributes' => [
41+
'name',
42+
'user_id',
43+
'actionable_type',
44+
'actionable_id',
45+
],
46+
],
47+
],
48+
])->json('data');
49+
}
50+
}

0 commit comments

Comments
 (0)