Skip to content

Commit

Permalink
Make use of lorisleiva/laravel-actions
Browse files Browse the repository at this point in the history
  • Loading branch information
nasrulhazim committed Oct 31, 2024
1 parent 67a8f82 commit 7e37e24
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 72 deletions.
2 changes: 1 addition & 1 deletion .phpunit.cache/test-results
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"pest_2.36.0","defects":[],"times":{"P\\Tests\\ResourceActionTest::__pest_evaluable_it_applies_constraints_for_update_or_create":0.228,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_handles_multiple_fields_for_hashing_and_encryption":0.267,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_applies_hashing_to_password_field":0.138,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_applies_both_hashing_and_encryption_to_specified_fields":0.135,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_does_not_apply_transformation_if_optional_field_is_missing":0.003,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_removes_confirmation_fields_from_inputs":0,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_validates_required_fields":0.001,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_throws_exception_if_model_is_not_set":0.067,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_uses_transactions_during_execution":0.077,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_creates_a_user_with_valid_data":0.133,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_has_make_action_command":0.006,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_can_make_an_API_action":0.002,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_can_make_an_action_with_model_option":0.001,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_can_make_an_action_without_model_option":0.002,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_can_make_a_menu_action":0.001}}
{"version":"pest_2.36.0","defects":[],"times":{"P\\Tests\\ResourceActionTest::__pest_evaluable_it_applies_constraints_for_update_or_create":0.183,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_handles_multiple_fields_for_hashing_and_encryption":0.24,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_applies_hashing_to_password_field":0.121,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_applies_both_hashing_and_encryption_to_specified_fields":0.122,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_does_not_apply_transformation_if_optional_field_is_missing":0.001,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_removes_confirmation_fields_from_inputs":0,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_validates_required_fields":0.001,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_throws_exception_if_model_is_not_set":0.061,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_uses_transactions_during_execution":0.068,"P\\Tests\\ResourceActionTest::__pest_evaluable_it_creates_a_user_with_valid_data":0.132,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_has_make_action_command":0.004,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_can_make_an_API_action":0.001,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_can_make_an_action_with_model_option":0.001,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_can_make_an_action_without_model_option":0.001,"P\\Tests\\LaravelActionTest::__pest_evaluable_it_can_make_a_menu_action":0.001}}
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"cleaniquecoders/laravel-contract": "^1.0",
"cleaniquecoders/traitify": "^1.0",
"illuminate/contracts": "^10.0||^11.0",
"lorisleiva/laravel-actions": "^2.8",
"spatie/laravel-package-tools": "^1.16"
},
"require-dev": {
Expand Down
4 changes: 1 addition & 3 deletions src/LaravelAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@

namespace CleaniqueCoders\LaravelAction;

class LaravelAction
{
}
class LaravelAction {}
98 changes: 40 additions & 58 deletions src/ResourceAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
namespace CleaniqueCoders\LaravelAction;

use CleaniqueCoders\LaravelAction\Exceptions\ActionException;
use CleaniqueCoders\LaravelContract\Contracts\Execute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Lorisleiva\Actions\Concerns\AsAction;

abstract class ResourceAction implements Execute
abstract class ResourceAction
{
use AsAction;

/**
* The model class the action operates on.
*/
Expand All @@ -20,7 +22,7 @@ abstract class ResourceAction implements Execute
/**
* Input data for the action.
*/
protected array $inputs;
protected array $inputs = [];

/**
* Fields to use for constraint-based operations.
Expand All @@ -40,7 +42,7 @@ abstract class ResourceAction implements Execute
/**
* The Eloquent model record.
*/
protected Model $record;
protected ?Model $record = null;

/**
* Constructor to initialize input data.
Expand All @@ -50,11 +52,6 @@ public function __construct(array $inputs = [])
$this->inputs = $inputs;
}

/**
* Abstract method to define validation rules for the action.
*/
abstract public function rules(): array;

/**
* Generic setter for properties.
*
Expand All @@ -76,7 +73,7 @@ public function setProperty(string $property, array $value): self
/**
* Retrieve the current record.
*/
public function getRecord(): Model
public function getRecord(): ?Model
{
return $this->record;
}
Expand All @@ -90,7 +87,35 @@ public function inputs(): array
}

/**
* Hash specified fields in the inputs or constraints.
* Main action execution logic.
*/
public function handle(): Model
{
$this->validateInputs();
$this->transformFields();
$this->removeConfirmationFields();

return $this->record = DB::transaction(function () {
return ! empty($this->constrainedBy)
? $this->model()::updateOrCreate($this->constrainedBy, $this->inputs)
: $this->model()::create($this->inputs);
});
}

/**
* Conditionally validate inputs if rules are defined.
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function validateInputs(): void
{
if (method_exists($this, 'rules') && ! empty($this->rules())) {
Validator::make($this->inputs, $this->rules())->validate();
}
}

/**
* Transform specified fields in the inputs.
*/
protected function transformFields(): void
{
Expand All @@ -111,14 +136,11 @@ public function removeConfirmationFields(): void
*/
protected function applyTransformationOnFields(array $fields, callable $transformation): void
{
$transformFields = function (&$value, $key) use ($fields, $transformation) {
if (in_array($key, $fields, true)) {
$value = $transformation($value);
foreach ($fields as $field) {
if (isset($this->inputs[$field])) {
$this->inputs[$field] = $transformation($this->inputs[$field]);
}
};

array_walk_recursive($this->inputs, $transformFields);
array_walk_recursive($this->constrainedBy, $transformFields);
}
}

/**
Expand All @@ -138,44 +160,4 @@ public function model(): string

return $this->model;
}

/**
* Preparation method for the action.
*/
public function prepare(): void
{
// Placeholder for child classes to implement custom preparation.
}

/**
* Validates the inputs against the defined rules.
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function validateInputs(): void
{
Validator::make(
array_merge($this->constrainedBy, $this->inputs),
$this->rules()
)->validate();
}

/**
* Execute the action with preparation, validation, and data processing.
*
* @throws \Illuminate\Validation\ValidationException
*/
public function execute(): Model
{
$this->prepare();
$this->validateInputs();
$this->transformFields();
$this->removeConfirmationFields();

return $this->record = DB::transaction(function () {
return ! empty($this->constrainedBy)
? $this->model()::updateOrCreate($this->constrainedBy, $this->inputs)
: $this->model()::create($this->inputs);
});
}
}
20 changes: 10 additions & 10 deletions tests/ResourceActionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
$action = new CreateUserAction($inputs);

// Act
$record = $action->execute();
$record = $action->handle();

// Assert
expect($record)->toBeInstanceOf(User::class)
Expand All @@ -41,7 +41,7 @@
$action = new CreateUserAction($inputs);

// Act & Assert
expect(fn () => $action->execute())->toThrow(\Illuminate\Validation\ValidationException::class);
expect(fn () => $action->handle())->toThrow(\Illuminate\Validation\ValidationException::class);
});

// it throws exception if model is not set
Expand All @@ -60,7 +60,7 @@
};

// Act & Assert
expect(fn () => $stubAction->execute())->toThrow(ActionException::class);
expect(fn () => $stubAction->handle())->toThrow(ActionException::class);
});

// it applies hashing to password field
Expand All @@ -76,7 +76,7 @@
$action->setProperty('hashFields', ['password']); // Use setProperty to define hash fields

// Act
$record = $action->execute();
$record = $action->handle();

// Assert
expect(Hash::check('secretpassword', $record->password))->toBeTrue();
Expand All @@ -97,7 +97,7 @@
$action->setProperty('encryptFields', ['ssn']);

// Act
$record = $action->execute();
$record = $action->handle();

// Assert
expect(Hash::check('secretpassword', $record->password))->toBeTrue();
Expand All @@ -120,7 +120,7 @@
$action->setProperty('encryptFields', ['ssn', 'email']);

// Act
$record = $action->execute();
$record = $action->handle();

// Assert
// Only use Hash::check on fields known to be hashed
Expand Down Expand Up @@ -153,7 +153,7 @@
$action->setProperty('constrainedBy', ['id' => $existingUser->id]); // Use ID as a unique constraint for update

// Act
$record = $action->execute();
$record = $action->handle();

// Assert
expect($record->name)->toBe('John Doe Updated')
Expand Down Expand Up @@ -211,7 +211,7 @@
$mockQueryBuilder->shouldReceive('updateOrCreate')->andReturn(Mockery::mock(User::class));

// Act
$record = $action->execute();
$record = $action->handle();

// Assert
expect($record)->toBeInstanceOf(User::class);
Expand All @@ -230,9 +230,9 @@
$action->setProperty('hashFields', ['security_answer']); // 'security_answer' is not present in inputs

// Act
$record = $action->execute();
$record = $action->handle();

// Assert
expect($record)->toBeInstanceOf(User::class); // Check the action executed successfully
expect($record)->toBeInstanceOf(User::class); // Check the action handled successfully
expect($action->inputs())->not->toHaveKey('security_answer'); // Ensure no transformation occurred on missing field
});

0 comments on commit 7e37e24

Please sign in to comment.