Skip to content

Commit 5887a09

Browse files
authored
Add groups, fix validation bugs, improve robustness (#36)
1 parent 2b6927f commit 5887a09

30 files changed

+792
-326
lines changed

.php_cs.dist renamed to .php-cs-fixer.dist.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
->exclude('tests/Feature/__snapshots__')
77
->in(__DIR__);
88

9-
return PhpCsFixer\Config::create()
9+
return (new PhpCsFixer\Config)
1010
->setRules([
1111
'@PSR2' => true,
1212
'method_argument_space' => ['on_multiline' => 'ignore'],
1313
'ordered_imports' => [
14-
'sortAlgorithm' => 'alpha',
14+
'sort_algorithm' => 'alpha',
1515
],
1616
'braces' => [
1717
'allow_single_line_closure' => true,
1818
],
19-
'trailing_comma_in_multiline_array' => true,
19+
'trailing_comma_in_multiline' => true,
2020
'single_quote' => false,
2121
'space_after_semicolon' => true,
2222
'single_blank_line_before_namespace' => true,

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
}
2020
],
2121
"require": {
22-
"php": "^8.0",
23-
"illuminate/support": "^10.0"
22+
"php": "^8.1",
23+
"illuminate/support": "^9.0|^10.0"
2424
},
2525
"require-dev": {
26-
"orchestra/testbench": "^8.0",
26+
"orchestra/testbench": "^7.6|^8.0",
2727
"phpunit/phpunit": "^9.0",
2828
"friendsofphp/php-cs-fixer": "^3.6"
2929
},

config/custom-fields.php

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,67 @@
11
<?php
22

33
return [
4-
'form_name' => env('CUSTOM_FIELDS_FORM_NAME', 'custom_fields'),
4+
'form-name' => env('CUSTOM_FIELDS_FORM_NAME', 'custom_fields'),
55

66
'tables' => [
77
'fields' => env('CUSTOM_FIELDS_TABLE', 'custom_fields'),
88
'field-responses' => env('CUSTOM_FIELD_RESPONSES_TABLE', 'custom_field_responses'),
99
],
10+
11+
'models' => [
12+
'custom-field' => \Givebutter\LaravelCustomFields\Models\CustomField::class,
13+
'custom-field-response' => \Givebutter\LaravelCustomFields\Models\CustomFieldResponse::class,
14+
],
15+
16+
/*
17+
| -------------------------------------------------------------------
18+
| Field Types
19+
| -------------------------------------------------------------------
20+
|
21+
| The list of all custom field types. You can register
22+
| your own custom field types here. Make sure to also
23+
| register the corresponding response type below.
24+
*/
25+
'fields' => [
26+
'checkbox' => \Givebutter\LaravelCustomFields\FieldTypes\CheckboxFieldType::class,
27+
'number' => \Givebutter\LaravelCustomFields\FieldTypes\NumberFieldType::class,
28+
'radio' => \Givebutter\LaravelCustomFields\FieldTypes\RadioFieldType::class,
29+
'select' => \Givebutter\LaravelCustomFields\FieldTypes\SelectFieldType::class,
30+
'textarea' => \Givebutter\LaravelCustomFields\FieldTypes\TextareaFieldType::class,
31+
'text' => \Givebutter\LaravelCustomFields\FieldTypes\TextFieldType::class,
32+
],
33+
34+
/*
35+
| -------------------------------------------------------------------
36+
| Response Types
37+
| -------------------------------------------------------------------
38+
|
39+
| The list of all custom field response types. You can register
40+
| your own custom field responses here. Make sure to also
41+
| register the corresponding field type above.
42+
*/
43+
'responses' => [
44+
'checkbox' => \Givebutter\LaravelCustomFields\ResponseTypes\CheckboxResponseType::class,
45+
'number' => \Givebutter\LaravelCustomFields\ResponseTypes\NumberResponseType::class,
46+
'radio' => \Givebutter\LaravelCustomFields\ResponseTypes\RadioResponseType::class,
47+
'select' => \Givebutter\LaravelCustomFields\ResponseTypes\SelectResponseType::class,
48+
'textarea' => \Givebutter\LaravelCustomFields\ResponseTypes\TextareaResponseType::class,
49+
'text' => \Givebutter\LaravelCustomFields\ResponseTypes\TextResponseType::class,
50+
],
51+
52+
/*
53+
| -------------------------------------------------------------------
54+
| Value Fields
55+
| -------------------------------------------------------------------
56+
|
57+
| The list of all value columns that can hold a response value on the
58+
| custom_field_responses table.
59+
*/
60+
'value-fields' => [
61+
'value_int',
62+
'value_str',
63+
'value_text',
64+
'value_json',
65+
],
66+
1067
];

database/factories/CustomFieldFactory.php

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Exception;
66
use Faker\Provider\Lorem;
7+
use Givebutter\LaravelCustomFields\Enums\CustomFieldType;
78
use Givebutter\LaravelCustomFields\Models\CustomField;
89
use Illuminate\Database\Eloquent\Factories\Factory;
910

@@ -23,23 +24,15 @@ class CustomFieldFactory extends Factory
2324
*/
2425
public function definition()
2526
{
26-
$typesRequireAnswers = [
27-
CustomField::TYPE_TEXT => false,
28-
CustomField::TYPE_RADIO => true,
29-
CustomField::TYPE_SELECT => true,
30-
CustomField::TYPE_NUMBER => false,
31-
CustomField::TYPE_CHECKBOX => false,
32-
CustomField::TYPE_TEXTAREA => false,
33-
];
34-
35-
$type = array_keys($typesRequireAnswers)[rand(0, count($typesRequireAnswers) - 1)]; // Pick a random type
27+
/** @var CustomFieldType $type */
28+
$type = $this->faker->randomElement(CustomFieldType::cases());
3629

3730
return [
38-
'type' => $type,
31+
'type' => $type->value,
3932
'required' => false,
4033
'title' => Lorem::sentence(3),
4134
'description' => Lorem::sentence(3),
42-
'answers' => $typesRequireAnswers ? Lorem::words() : [],
35+
'answers' => $type->requiresAnswers() ? Lorem::words() : [],
4336
];
4437
}
4538

@@ -48,7 +41,7 @@ public function definition()
4841
*/
4942
public function withTypeCheckbox()
5043
{
51-
$this->model->type = CustomField::TYPE_CHECKBOX;
44+
$this->model->type = CustomFieldType::CHECKBOX;
5245

5346
return $this;
5447
}
@@ -58,7 +51,7 @@ public function withTypeCheckbox()
5851
*/
5952
public function withTypeNumber()
6053
{
61-
$this->model->type = CustomField::TYPE_NUMBER;
54+
$this->model->type = CustomFieldType::NUMBER;
6255

6356
return $this;
6457
}
@@ -70,7 +63,7 @@ public function withTypeNumber()
7063
*/
7164
public function withTypeRadio($answerCount = 3)
7265
{
73-
$this->model->type = CustomField::TYPE_RADIO;
66+
$this->model->type = CustomFieldType::RADIO;
7467

7568
return $this->withAnswers($answerCount);
7669
}
@@ -82,7 +75,7 @@ public function withTypeRadio($answerCount = 3)
8275
*/
8376
public function withTypeSelect($optionCount = 3)
8477
{
85-
$this->model->type = CustomField::TYPE_SELECT;
78+
$this->model->type = CustomFieldType::SELECT;
8679

8780
return $this->withAnswers($optionCount);
8881
}
@@ -92,7 +85,7 @@ public function withTypeSelect($optionCount = 3)
9285
*/
9386
public function withTypeText()
9487
{
95-
$this->model->type = CustomField::TYPE_TEXT;
88+
$this->model->type = CustomFieldType::TEXT;
9689

9790
return $this;
9891
}
@@ -102,7 +95,7 @@ public function withTypeText()
10295
*/
10396
public function withTypeTextArea()
10497
{
105-
$this->model->type = CustomField::TYPE_TEXTAREA;
98+
$this->model->type = CustomFieldType::TEXTAREA;
10699

107100
return $this;
108101
}

database/migrations/create_custom_fields_tables.php.stub

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ return new class extends Migration
1717
$table->increments('id');
1818
$table->unsignedInteger('model_id');
1919
$table->string('model_type');
20+
$table->string('group')->nullable();
2021
$table->string('type');
2122
$table->boolean('required')->default(false);
2223
$table->json('answers')->nullable();
2324
$table->string('title');
2425
$table->string('description')->nullable();
2526
$table->string('default_value')->nullable();
26-
$table->string('order');
27+
$table->integer('order');
2728
$table->timestamps();
2829
$table->timestamp('archived_at')->nullable();
2930
$table->softDeletes();
@@ -38,6 +39,7 @@ return new class extends Migration
3839
$table->string('value_str')->nullable();
3940
$table->text('value_text')->nullable();
4041
$table->integer('value_int')->nullable();
42+
$table->json('value_json')->nullable();
4143
$table->timestamps();
4244
});
4345
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Givebutter\LaravelCustomFields\Collections;
4+
5+
use Givebutter\LaravelCustomFields\Models\CustomField;
6+
use Illuminate\Database\Eloquent\Collection;
7+
8+
class CustomFieldCollection extends Collection
9+
{
10+
public function toValidationRules(): array
11+
{
12+
return $this->map(fn (CustomField $field): array => $field->validation_rules)
13+
->flatMap(fn (array $rules): array => $rules)
14+
->toArray();
15+
}
16+
17+
public function toValidationAttributes(): array
18+
{
19+
return $this->map(fn (CustomField $field): array => $field->validation_attributes)
20+
->flatMap(fn (array $rules): array => $rules)
21+
->toArray();
22+
}
23+
24+
public function toValidationMessages(): array
25+
{
26+
return $this->map(fn (CustomField $field): array => $field->validation_messages)
27+
->flatMap(fn (array $rules): array => $rules)
28+
->toArray();
29+
}
30+
}

src/Enums/CustomFieldType.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Givebutter\LaravelCustomFields\Enums;
4+
5+
enum CustomFieldType: string
6+
{
7+
case CHECKBOX = 'checkbox';
8+
case NUMBER = 'number';
9+
case RADIO = 'radio';
10+
case SELECT = 'select';
11+
case TEXT = 'text';
12+
case TEXTAREA = 'textarea';
13+
14+
public function requiresAnswers(): bool
15+
{
16+
return in_array($this, [
17+
self::RADIO,
18+
self::SELECT,
19+
]);
20+
}
21+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Givebutter\LaravelCustomFields\FieldTypes;
4+
5+
class CheckboxFieldType extends FieldType
6+
{
7+
public function validationRules(array $attributes): array
8+
{
9+
return [
10+
$this->validationPrefix . $this->field->id => [
11+
$this->requiredRule($attributes['required']),
12+
$attributes['required'] ? 'accepted' : function ($fail, $value, $attribute) {
13+
if (! in_array($value, ['on', 'off', 'yes', 'no', 0, 1, '0', '1', true, false, 'true', 'false'])) {
14+
$fail('The :attribute response cannot be understood.');
15+
}
16+
},
17+
],
18+
];
19+
}
20+
}

src/FieldTypes/FieldType.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace Givebutter\LaravelCustomFields\FieldTypes;
4+
5+
use Givebutter\LaravelCustomFields\Models\CustomField;
6+
7+
abstract class FieldType
8+
{
9+
protected string $validationPrefix = 'custom_fields.field_';
10+
11+
public function __construct(
12+
protected CustomField $field,
13+
) {
14+
//
15+
}
16+
17+
public function setValidationPrefix(string $prefix): self
18+
{
19+
$this->validationPrefix = $prefix;
20+
21+
return $this;
22+
}
23+
24+
public function validationRules(array $attributes): array
25+
{
26+
return [
27+
$this->validationPrefix . $this->field->id => ['required'],
28+
];
29+
}
30+
31+
public function validationAttributes(): array
32+
{
33+
return [
34+
$this->validationPrefix . $this->field->id => $this->field->title,
35+
];
36+
}
37+
38+
public function validationMessages(): array
39+
{
40+
return [];
41+
}
42+
43+
protected function requiredRule(bool $required): string
44+
{
45+
return $required ? 'required' : 'nullable';
46+
}
47+
}

src/FieldTypes/NumberFieldType.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Givebutter\LaravelCustomFields\FieldTypes;
4+
5+
class NumberFieldType extends FieldType
6+
{
7+
public function validationRules(array $attributes): array
8+
{
9+
return [
10+
$this->validationPrefix . $this->field->id => [
11+
$this->requiredRule($attributes['required']),
12+
'integer',
13+
],
14+
];
15+
}
16+
}

0 commit comments

Comments
 (0)