From 1ce70661353136492084cbf87140ba67bd9e6973 Mon Sep 17 00:00:00 2001 From: Mohammad Emran Date: Tue, 5 Jul 2022 20:31:43 +0600 Subject: [PATCH 1/3] Add field-level validation rules support --- src/CrudResource.php | 9 ++++ src/Fields/Field.php | 106 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/CrudResource.php b/src/CrudResource.php index 4809cc2..24223b2 100644 --- a/src/CrudResource.php +++ b/src/CrudResource.php @@ -22,6 +22,9 @@ public function filters(): array public function buildList(): void { foreach ($this->fields() as $field) { + $field->setRequest($this->crud->getRequest()) + ->setOperation($this->crud->getCurrentOperation()); + if ($field->isShownOnIndex()) { $this->crud->addColumn($field->columnDefinition()); } @@ -39,6 +42,9 @@ public function buildList(): void public function buildCreateForm(): void { foreach ($this->fields() as $field) { + $field->setRequest($this->crud->getRequest()) + ->setOperation($this->crud->getCurrentOperation()); + if ($field->isShownOnCreation()) { $this->crud->addField($field->fieldDefinition()); } @@ -48,6 +54,9 @@ public function buildCreateForm(): void public function buildUpdateForm(): void { foreach ($this->fields() as $field) { + $field->setRequest($this->crud->getRequest()) + ->setOperation($this->crud->getCurrentOperation()); + if ($field->isShownOnUpdate()) { $this->crud->addField($field->fieldDefinition()); } diff --git a/src/Fields/Field.php b/src/Fields/Field.php index 43ae10d..ed1c2de 100644 --- a/src/Fields/Field.php +++ b/src/Fields/Field.php @@ -2,10 +2,14 @@ namespace FigLab\CrudResource\Fields; +use Illuminate\Contracts\Validation\Rule; +use Illuminate\Http\Request; use Illuminate\Support\Str; abstract class Field { + private const CREATE_OPERATION = 'create'; + /** * The displayable name of the field. */ @@ -96,11 +100,36 @@ abstract class Field */ protected \Closure $displayCallback; + /** + * The validation rules for create and update forms. + */ + protected array $rules = []; + + /** + * The validation rules for create form. + */ + protected array $creationRules = []; + + /** + * The validation rules for update form. + */ + protected array $updateRules = []; + /** * The definition of the field to return. */ protected array $props = []; + /** + * Request object from CrudPanel. + */ + protected Request $request; + + /** + * CRUD operation of the request (Ex: create / update / revision / delete) + */ + protected string $operation; + /** * Private constructor to avoid direct instance creation */ @@ -118,6 +147,26 @@ public static function make(...$arguments): static return new static(...$arguments); } + /** + * Pass the Request from CrudPanel to the field. + */ + public function setRequest(Request $request): self + { + $this->request = $request; + + return $this; + } + + /** + * Pass the operation name from CrudPanel to the field. + */ + public function setOperation(string $operation): self + { + $this->operation = $operation; + + return $this; + } + /** * Default value for the field. */ @@ -392,6 +441,52 @@ public function exceptOnForms(): self return $this; } + /** + * Set the validation rules for the field. + */ + public function rules(string | array | Rule $rules): self + { + $this->rules = $rules instanceof Rule || is_string($rules) ? func_get_args() : $rules; + + return $this; + } + + /** + * Set the validation rules for the field. + */ + public function creationRules(string | array | Rule $rules): self + { + $this->creationRules = $rules instanceof Rule || is_string($rules) ? func_get_args() : $rules; + + return $this; + } + + /** + * Determine the validation rules for the field in the time of creation. + */ + protected function getCreationRules(): array + { + return array_merge_recursive($this->rules, $this->creationRules); + } + + /** + * Set the validation rules for the field. + */ + public function updateRules(string | array | Rule $rules): self + { + $this->updateRules = $rules instanceof Rule || is_string($rules) ? func_get_args() : $rules; + + return $this; + } + + /** + * Determine the validation rules for the field in the time of update. + */ + protected function getUpdateRules(): array + { + return array_merge_recursive($this->rules, $this->updateRules); + } + /** * Return the Backpack column definition, after merging with existing properties from inherited field. */ @@ -414,13 +509,12 @@ public function columnDefinition(): array return array_merge($props, $this->props); } - public function buildSubFields(): array { $subFields = []; foreach ($this->props['subfields'] ?? [] as $field) { if ($field->isShownOnCreation()) { - $subFields[] = $field->fieldDefinition(); + $subFields[] = $field->fieldDefinition(); } } @@ -444,6 +538,14 @@ public function fieldDefinition(): array ], ]; + $validationRules = $this->operation === self::CREATE_OPERATION + ? $this->getCreationRules() + : $this->getUpdateRules(); + + if (count($validationRules) > 0) { + $props['validationRules'] = $validationRules; + } + if (isset($this->props['subfields'])) { $this->props['subfields'] = $this->buildSubFields(); } From d8bab630bbf79baf27fc3504193203398941784c Mon Sep 17 00:00:00 2001 From: Mohammad Emran Date: Tue, 5 Jul 2022 20:56:06 +0600 Subject: [PATCH 2/3] Add resource-level validation rules support --- src/CrudResource.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/CrudResource.php b/src/CrudResource.php index 24223b2..b99199b 100644 --- a/src/CrudResource.php +++ b/src/CrudResource.php @@ -19,6 +19,18 @@ public function filters(): array return []; } + /** @return array> */ + public function validationRules(): array + { + return []; + } + + /** @return array */ + public function validationMessages(): array + { + return []; + } + public function buildList(): void { foreach ($this->fields() as $field) { @@ -49,6 +61,13 @@ public function buildCreateForm(): void $this->crud->addField($field->fieldDefinition()); } } + + if (count($this->validationRules()) > 0) { + $this->crud->setValidation( + $this->validationRules(), + $this->validationMessages() + ); + } } public function buildUpdateForm(): void @@ -61,5 +80,12 @@ public function buildUpdateForm(): void $this->crud->addField($field->fieldDefinition()); } } + + if (count($this->validationRules()) > 0) { + $this->crud->setValidation( + $this->validationRules(), + $this->validationMessages() + ); + } } } From 27fee8b36d21897dc951f1e9ff5e979fe16a773c Mon Sep 17 00:00:00 2001 From: Mohammad Emran Date: Wed, 6 Jul 2022 17:14:59 +0600 Subject: [PATCH 3/3] Add initial documentation --- docs/crud_resource.md | 97 +++++++++++++++++++++++++++++++++++++++++++ docs/readme.md | 4 ++ docs/validation.md | 79 +++++++++++++++++++++++++++++++++++ readme.md | 2 +- 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 docs/crud_resource.md create mode 100644 docs/readme.md create mode 100644 docs/validation.md diff --git a/docs/crud_resource.md b/docs/crud_resource.md new file mode 100644 index 0000000..023b89a --- /dev/null +++ b/docs/crud_resource.md @@ -0,0 +1,97 @@ +# Defining Crud Resource + +It's super easy to create a CrudResource for your model. To get started, we suggest creating a `CrudResources` directory +within your **app** folder and creating the resource classes there. + +To start with, all you need is to create a class that extends the `\FigLab\CrudResource\CrudResource` abstract class and +define the `fields()` method. + +Here's an example for the default `User` model that comes pre-installed with Laravel: + +```php +sortable(), + + Email::make('Email'), + + Password::make('Password') + ->size(6) + ->onlyOnForms(), + + Password::make('Confirm Password', 'password_confirmation') + ->size(6) + ->onlyOnForms(), + ]; + } +} +``` + +Now, to use this CrudResource, you need to configure your controller accordingly. Here's the `UserController.php` that +shows how to do it: + +```php +crud->setModel(\App\Models\User::class); + $this->crud->setRoute(config('backpack.base.route_prefix') . '/users'); + $this->crud->setEntityNameStrings('user', 'users'); + + $this->crudResource = new UserCrudResource($this->crud); + } + + protected function setupListOperation(): void + { + $this->crudResource->buildList(); + } + + protected function setupCreateOperation(): void + { + $this->crud->setValidation(UserStoreRequest::class); + + $this->crudResource->buildCreateForm(); + } + + protected function setupUpdateOperation(): void + { + $this->crud->setValidation(UserUpdateRequest::class); + + $this->crudResource->buildUpdateForm(); + } +} +``` diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 0000000..2fc89dd --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,4 @@ +# Documentation + +- [Create a CrudResource](crud_resource.md) +- [Validation Rules](validation.md) diff --git a/docs/validation.md b/docs/validation.md new file mode 100644 index 0000000..5da6553 --- /dev/null +++ b/docs/validation.md @@ -0,0 +1,79 @@ +# Validation + +There are two ways in which you can add validation rules for your model. + +### Field-level Validation Rules + +You can specify the validation rules for each of the fields within your CrudResource. Here's an example: + +```php +public function fields(): array +{ + $id = $this->crud->getRequest()->input('id') ?? $this->crud->getRequest()->route('id'); + + return [ + Text::make('Name') + ->rules('required', 'min:5', 'max:255') + ->sortable(), + + Email::make('Email') + ->rules('required') + ->creationRules('unique:users,email') + ->updateRules('unique:users,email,'.$id), + + Password::make('Password') + ->size(6) + ->rules(['confirmed', 'min:8']) + ->onlyOnForms(), + + Password::make('Confirm Password', 'password_confirmation') + ->size(6) + ->creationRules('required') + ->onlyOnForms(), + ]; +} +``` + +As shown in the example, there are three methods to use: + +- **rules**: adds the validation rule for both create and update forms +- **creationRules**: adds the validation rule only for create form +- **updateRules**: adds the validation rule only for update form + +You can pass an array of rules, or can specify the rules as individual parameters. + +### Resource-level Validation Rules + +In addition to the field-level validation, the validation rules/messages can also be added to the CrudResource itself. Example: + +```php +/** @inheritDoc */ +public function validationRules(): array +{ + $id = $this->crud->getRequest()->get('id') ?? $this->crud->getRequest()->route('id'); + + $rules = [ + 'name' => 'required|min:5|max:255', + 'role' => 'required', + ]; + + $rules['email'] = $this->crud->getOperation() === 'create' + ? 'required|unique:users,email' + : 'required|unique:users,email,'.$id; + + $rules['password'] = $this->crud->getOperation() === 'create' + ? 'required|confirmed' + : 'confirmed'; + + return $rules; +} + +/** @inheritDoc */ +public function validationMessages(): array +{ + return [ + 'name.required' => 'You gotta give it a name, man.', + 'name.min' => 'You came up short. Try more than 2 characters.', + ]; +} +``` diff --git a/readme.md b/readme.md index 7007eee..e095d62 100644 --- a/readme.md +++ b/readme.md @@ -113,7 +113,7 @@ composer require figlabhq/crud-resource-for-backpack ## Documentation -Coming soon...stay tuned 😅 +Please see the [documentation](docs/readme.md) section for further details of the functionality. ## Change log