Skip to content

Commit 22ac406

Browse files
author
midesweb
committed
Integrate new functionalities
1 parent 47f41b1 commit 22ac406

18 files changed

+2616
-6
lines changed

README.md

Lines changed: 359 additions & 5 deletions
Large diffs are not rendered by default.

README_es.md

Lines changed: 845 additions & 0 deletions
Large diffs are not rendered by default.

src/ActionHandler.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EscuelaIT\APIKit;
6+
7+
use Illuminate\Support\Facades\Auth;
8+
use Illuminate\Support\Facades\Validator;
9+
use Negartarh\APIWrapper\Facades\APIResponse;
10+
11+
trait ActionHandler
12+
{
13+
public function handleAction(ActionService $actionService) {
14+
$user = Auth::user();
15+
16+
$validator = Validator::make(request()->all(), [
17+
'type' => ['required', 'string', 'max:250'],
18+
'relatedIds' => ['required', 'array'],
19+
'data' => ['present'],
20+
]);
21+
22+
if($validator->fails()) {
23+
return APIResponse::unprocessableEntity($validator->errors());
24+
}
25+
26+
if(! $actionService->hasActionType(request()->type)) {
27+
return APIResponse::unprocessableEntity([], 'The action type is not valid.');
28+
}
29+
30+
$response = $actionService->processAction($validator->validated(), $user);
31+
if ($response->isSuccess()) {
32+
return APIResponse::ok($response->getData(), $response->getMessage());
33+
}
34+
return APIResponse::unprocessableEntity($response->getErrors(), $response->getMessage());
35+
}
36+
}

src/ActionResult.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EscuelaIT\APIKit;
6+
7+
class ActionResult
8+
{
9+
private bool $success;
10+
private array $errors = [];
11+
private string $message;
12+
private array $data = [];
13+
14+
private function __construct($success, $message = '', $errors = [], $data = []) {
15+
$this->success = $success;
16+
$this->message = $message;
17+
$this->errors = $errors;
18+
$this->data = $data;
19+
}
20+
21+
public static function success(string $message = 'Ok', array $data = []): self {
22+
return new self(true, $message, [], $data);
23+
}
24+
25+
public static function error(array $errors = [], string $message = 'Error'): self {
26+
$normalizedErrors = [];
27+
foreach ($errors as $field => $value) {
28+
$normalizedErrors[$field] = is_string($value) ? [$value] : $value;
29+
}
30+
31+
return new self(false, $message, $normalizedErrors);
32+
}
33+
34+
public function isSuccess(): bool {
35+
return $this->success;
36+
}
37+
public function getErrors(): array {
38+
return $this->errors;
39+
}
40+
public function getMessage(): string {
41+
return $this->message;
42+
}
43+
public function getData(): array {
44+
return $this->data;
45+
}
46+
47+
public function toArray(): array {
48+
return [
49+
'success' => $this->success,
50+
'errors' => $this->errors,
51+
'message' => $this->message,
52+
'data' => $this->data,
53+
];
54+
}
55+
}

src/ActionService.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EscuelaIT\APIKit;
6+
7+
use Illuminate\Notifications\Action;
8+
use EscuelaIT\APIKit\Exceptions\ActionModelNotDefinedException;
9+
10+
class ActionService
11+
{
12+
protected string $actionModel;
13+
protected array $actionTypes = [];
14+
protected int $maxModelsPerAction = 100;
15+
protected string $identifierField = 'id';
16+
protected array $actionData;
17+
protected $query;
18+
protected $user;
19+
20+
public function hasActionType(string $type): bool
21+
{
22+
return isset($this->actionTypes[$type]);
23+
}
24+
25+
public function processAction($actionData, $user): ActionResult {
26+
$this->actionData = $actionData;
27+
$this->user = $user;
28+
$this->query = $this->createQuery();
29+
$this->queryModels();
30+
31+
if($this->query->count() > $this->maxModelsPerAction) {
32+
return ActionResult::error(
33+
[],
34+
"The number of models to process exceeds the maximum allowed ({$this->maxModelsPerAction})."
35+
);
36+
}
37+
38+
return $this->getActionClass()->processAction();
39+
}
40+
41+
protected function createQuery()
42+
{
43+
if (empty($this->actionModel)) {
44+
throw new ActionModelNotDefinedException(static::class);
45+
}
46+
return $this->actionModel::query();
47+
}
48+
49+
public function queryModels() {
50+
return $this->query->whereIn($this->identifierField, $this->actionData['relatedIds']);
51+
}
52+
53+
private function getModels() {
54+
return $this->query->get();
55+
}
56+
57+
private function getActionClass() : CrudAction
58+
{
59+
$actionClass = $this->actionTypes[$this->actionData['type']];
60+
return new $actionClass($this->getModels(), $this->actionData['data'], $this->user);
61+
}
62+
}

src/Actions/DeleteAction.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace EscuelaIT\APIKit\Actions;
4+
5+
use EscuelaIT\APIKit\CrudAction;
6+
use EscuelaIT\APIKit\ActionResult;
7+
use EscuelaIT\APIKit\Exceptions\UnauthenticatedActionException;
8+
9+
class DeleteAction extends CrudAction {
10+
public function handle(): ActionResult {
11+
if(! $this->user) {
12+
throw new UnauthenticatedActionException();
13+
}
14+
$numDeleted = 0;
15+
$deleteElems = [];
16+
foreach($this->models as $model) {
17+
if($this->user->can('delete', $model)) {
18+
$model->delete();
19+
$deleteElems[] = $model->id;
20+
$numDeleted++;
21+
}
22+
}
23+
$message = "Borrados $numDeleted " . ($numDeleted == 1 ? 'elemento' : 'elementos') . " con éxito";
24+
return $this->createActionResultSuccess($message, [
25+
'delete_count' => $numDeleted,
26+
'delete_elems' => $deleteElems,
27+
]);
28+
}
29+
}

src/CrudAction.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EscuelaIT\APIKit;
6+
7+
use Illuminate\Notifications\Action;
8+
use Illuminate\Support\Facades\Validator;
9+
10+
abstract class CrudAction
11+
{
12+
13+
protected $models;
14+
protected $data;
15+
protected $user;
16+
protected $validationErrors;
17+
18+
public function __construct($models, $data, $user) {
19+
$this->models = $models;
20+
$this->data = $data;
21+
$this->user = $user;
22+
}
23+
24+
abstract public function handle(): ActionResult;
25+
26+
public function processAction(): ActionResult
27+
{
28+
if( $this->isValidData() ) {
29+
return $this->handle();
30+
} else {
31+
return ActionResult::error(
32+
$this->validationErrors ?? [],
33+
'The provided data is not valid.'
34+
);
35+
}
36+
}
37+
38+
protected function validationRules(): array {
39+
return [];
40+
}
41+
42+
protected function isValidData(): bool {
43+
$validator = Validator::make($this->data, $this->validationRules());
44+
$this->validationErrors = $validator->errors()->toArray();
45+
return ! $validator->fails();
46+
}
47+
48+
public function getModels() {
49+
return $this->models;
50+
}
51+
52+
public function getData() {
53+
return $this->data;
54+
}
55+
56+
public function getUser() {
57+
return $this->user;
58+
}
59+
60+
protected function createActionResultSuccess(string $message, array $data = []): ActionResult {
61+
return ActionResult::success($message, [
62+
'msg' => $message,
63+
'action' => class_basename(static::class),
64+
'data' => $data,
65+
]);
66+
}
67+
68+
protected function createActionResultError(string $message = "Unprocessable action", array $errors = []): ActionResult {
69+
return ActionResult::error($errors, $message);
70+
}
71+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EscuelaIT\APIKit\Exceptions;
6+
7+
class ActionModelNotDefinedException extends \Exception
8+
{
9+
public function __construct(string $class = '')
10+
{
11+
$message = "The 'actionModel' property is not defined in the {$class} class. "
12+
.'You must define the model to use in your ActionService derived class.';
13+
14+
parent::__construct($message);
15+
}
16+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace EscuelaIT\APIKit\Exceptions;
4+
5+
class UnauthenticatedActionException extends \Exception
6+
{
7+
public function __construct()
8+
{
9+
parent::__construct('This action requires an authenticated user.');
10+
}
11+
}

src/ListService.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
class ListService
1111
{
1212
protected string $listModel;
13+
protected string $identifierField = 'id';
1314
protected $query;
1415
protected bool $paginated = true;
1516
protected ?array $availableFilterColumns = null;
@@ -88,6 +89,12 @@ public function getResults()
8889
return $this->query->get();
8990
}
9091

92+
public function getAllIds() {
93+
$this->paginated = false;
94+
$this->getResults();
95+
return $this->query->get()->pluck($this->identifierField);
96+
}
97+
9198
public function setSearchConfiguration(array $config): ListService
9299
{
93100
foreach ($config as $key => $value) {

0 commit comments

Comments
 (0)