Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 73 additions & 4 deletions docs/docs/4.0/actions/actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,23 @@ You can apply any filter or eager loadings as for an usual request:
POST: api/api/restify/posts/actions?action=publish-posts-action&id=1&filters=
```

This will apply the match for the `id = 1` and `filtetr` along with the match for the `repositories` payload you're sending.
This will apply the match for the `id = 1` and `filter` along with the match for the `repositories` payload you're sending.

### Modify query

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:

```php
class PublishPostAction extends Action
{
public static function indexQuery(RestifyRequest $request, $query)
{
$query->whereNotNull('published_at');
}

//...
}
```

## All

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

## Chunk

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:

```php
Expand All @@ -200,7 +214,6 @@ public function actions(RestifyRequest $request)
}
```


And available actions only for a specific repository id could be listed like:

```http request
Expand Down Expand Up @@ -277,3 +290,59 @@ class DisableProfileAction extends Action
//...
}
```

## Action Log

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.

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.

You can display them by attaching to the repository related for example:

```php
// PostRepository.php
use Binaryk\LaravelRestify\Fields\MorphToMany;
use Binaryk\LaravelRestify\Repositories\ActionLogRepository;

public static function related(): array
{
return [
'logs' => MorphToMany::make('actionLogs', 'actionLogs', ActionLogRepository::class),
];
}
```

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:

```json
[
{
"id": "1",
"type": "action_logs",
"attributes": {
"batch_id": "048686bb-cd22-41a7-a6db-3eba29678d74",
"user_id": "1",
"name": "Stored",
"actionable_type": "App\\Models\\Post",
"actionable_id": "1",
"target_type": "App\\Models\\Post",
"target_id": "1",
"model_type": "App\\Models\\Post",
"model_id": "1",
"fields": "",
"status": "finished",
"original": "",
"changes": [],
"exception": ""
},
"meta": {
"authorizedToShow": true,
"authorizedToStore": true,
"authorizedToUpdate": true,
"authorizedToDelete": true
}
}
]
```

Definitely you can use your own `ActionLogRepository` to represent the data returned, maybe you prefer to represent the user details or something else.
17 changes: 14 additions & 3 deletions src/Repositories/ActionLogRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,20 @@ class ActionLogRepository extends Repository
public function fields(RestifyRequest $request)
{
return [
field('actionable_type'),

field('actionable_id'),
field('batch_id')->readonly(),
field('user_id')->readonly(),
field('name')->readonly(),
field('actionable_type')->readonly(),
field('actionable_id')->readonly(),
field('target_type')->readonly(),
field('target_id')->readonly(),
field('model_type')->readonly(),
field('model_id')->readonly(),
field('fields')->readonly(),
field('status')->readonly(),
field('original')->readonly(),
field('changes')->readonly(),
field('exception')->readonly(),
];
}
}
8 changes: 4 additions & 4 deletions src/Repositories/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Binaryk\LaravelRestify\Repositories;

use Binaryk\LaravelRestify\Contracts\ActionLogable;
use Binaryk\LaravelRestify\Contracts\RestifySearchable;
use Binaryk\LaravelRestify\Controllers\RestResponse;
use Binaryk\LaravelRestify\Eager\Related;
Expand All @@ -15,6 +14,7 @@
use Binaryk\LaravelRestify\Filter;
use Binaryk\LaravelRestify\Http\Requests\RepositoryStoreBulkRequest;
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
use Binaryk\LaravelRestify\Models\Concerns\HasActionLogs;
use Binaryk\LaravelRestify\Models\CreationAware;
use Binaryk\LaravelRestify\Repositories\Concerns\InteractsWithAttachers;
use Binaryk\LaravelRestify\Repositories\Concerns\Mockable;
Expand Down Expand Up @@ -705,7 +705,7 @@ public function store(RestifyRequest $request)
}
}

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

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

if ($this->resource instanceof ActionLogable) {
if (in_array(HasActionLogs::class, class_uses_recursive($this->resource))) {
Restify::actionLog()
->forRepositoryUpdated($this->resource, $request->user())
->save();
Expand Down Expand Up @@ -842,7 +842,7 @@ public function detach(RestifyRequest $request, $repositoryId, Collection $pivot
public function destroy(RestifyRequest $request, $repositoryId)
{
$status = DB::transaction(function () use ($request) {
if ($this->resource instanceof ActionLogable) {
if (in_array(HasActionLogs::class, class_uses_recursive($this->resource))) {
Restify::actionLog()
->forRepositoryDestroy($this->resource, $request->user())
->save();
Expand Down
3 changes: 2 additions & 1 deletion tests/Controllers/RepositoryIndexControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public function test_using_custom_related_casts()
]);
}

public function test_repository_with_deep_relations()
public function test_repository_with_nested_relations()
{
CompanyRepository::partialMock()
->expects('related')
Expand All @@ -139,6 +139,7 @@ public function test_repository_with_deep_relations()
});

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

$this->assertCount(1, $response->json('data.0.relationships.users'));
Expand Down
3 changes: 1 addition & 2 deletions tests/Fixtures/Post/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

namespace Binaryk\LaravelRestify\Tests\Fixtures\Post;

use Binaryk\LaravelRestify\Contracts\ActionLogable;
use Binaryk\LaravelRestify\Contracts\RestifySearchable;
use Binaryk\LaravelRestify\Models\Concerns\HasActionLogs;
use Binaryk\LaravelRestify\Tests\Fixtures\User\User;
use Binaryk\LaravelRestify\Traits\InteractWithSearch;
use Illuminate\Database\Eloquent\Model;

class Post extends Model implements RestifySearchable, ActionLogable
class Post extends Model implements RestifySearchable
{
use InteractWithSearch, HasActionLogs;

Expand Down
6 changes: 6 additions & 0 deletions tests/Fixtures/Post/PublishPostAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@

use Binaryk\LaravelRestify\Actions\Action;
use Binaryk\LaravelRestify\Http\Requests\ActionRequest;
use Binaryk\LaravelRestify\Http\Requests\RestifyRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;

class PublishPostAction extends Action
{
public static $applied = [];

public static function indexQuery(RestifyRequest $request, $query)
{
$query->whereNotNull('published_at');
}

public function handle(ActionRequest $request, Collection $models): JsonResponse
{
static::$applied[] = $models;
Expand Down
50 changes: 50 additions & 0 deletions tests/Repositories/ActionLogRepositoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Binaryk\LaravelRestify\Tests\Repositories;

use Binaryk\LaravelRestify\Models\ActionLog;
use Binaryk\LaravelRestify\Repositories\ActionLogRepository;
use Binaryk\LaravelRestify\Restify;
use Binaryk\LaravelRestify\Tests\Fixtures\User\User;
use Binaryk\LaravelRestify\Tests\IntegrationTest;

class ActionLogRepositoryTest extends IntegrationTest
{
protected function setUp(): void
{
parent::setUp();

Restify::repositories([
ActionLogRepository::class,
]);
}

public function test_can_list_action_logs()
{
$this->authenticate();

$log = ActionLog::forRepositoryStored(
factory(User::class)->create(),
$this->authenticatedAs
);

$log->save();

$this->getJson(ActionLogRepository::uriKey())
->assertOk()
->assertJsonStructure([
'data' => [
[
'id',
'type',
'attributes' => [
'name',
'user_id',
'actionable_type',
'actionable_id',
],
],
],
])->json('data');
}
}