Skip to content

Commit b2f6dcc

Browse files
committed
feat: update validation of all fields including relations
1 parent c8b5433 commit b2f6dcc

21 files changed

+183
-35
lines changed

src/Contracts/FillableToMany.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
1515
use Illuminate\Database\Eloquent\Model;
1616
use LaravelJsonApi\Eloquent\Polymorphism\MorphMany;
17+
use LaravelJsonApi\Validation\Fields\IsValidated;
1718

18-
interface FillableToMany extends IsReadOnly
19+
interface FillableToMany extends IsReadOnly, IsValidated
1920
{
20-
2121
/**
2222
* Fill the model with the value of the JSON:API to-many relation.
2323
*

src/Contracts/FillableToOne.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
namespace LaravelJsonApi\Eloquent\Contracts;
1313

1414
use Illuminate\Database\Eloquent\Model;
15+
use LaravelJsonApi\Validation\Fields\IsValidated;
1516

16-
interface FillableToOne extends IsReadOnly
17+
interface FillableToOne extends IsReadOnly, IsValidated
1718
{
18-
1919
/**
2020
* Does the model need to exist in the database before the relation is filled?
2121
*

src/Fields/ArrayHash.php

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,12 @@
1515
use LaravelJsonApi\Core\Json\Hash;
1616
use LaravelJsonApi\Core\Support\Arr;
1717
use LaravelJsonApi\Validation\Fields\IsValidated;
18-
19-
use LaravelJsonApi\Validation\Fields\ValidatedWithKeyedSetOfRules;
20-
18+
use LaravelJsonApi\Validation\Fields\ValidatedWithArrayKeys;
2119
use LaravelJsonApi\Validation\Rules\JsonObject;
2220

23-
use function is_null;
24-
2521
class ArrayHash extends Attribute implements IsValidated
2622
{
27-
use ValidatedWithKeyedSetOfRules;
23+
use ValidatedWithArrayKeys;
2824

2925
/**
3026
* @var Closure|null
@@ -235,7 +231,7 @@ protected function deserialize($value)
235231
$value = ($this->keys)($value);
236232
}
237233

238-
if (is_null($value)) {
234+
if ($value === null) {
239235
return null;
240236
}
241237

@@ -251,7 +247,7 @@ protected function deserialize($value)
251247
*/
252248
protected function assertValue($value): void
253249
{
254-
if ((!is_null($value) && !is_array($value)) || (!empty($value) && !Arr::isAssoc($value))) {
250+
if (($value !== null && !is_array($value)) || (!empty($value) && !Arr::isAssoc($value))) {
255251
throw new \UnexpectedValueException(sprintf(
256252
'Expecting the value of attribute %s to be an associative array.',
257253
$this->name()

src/Fields/ArrayList.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@
1313

1414
use Illuminate\Support\Arr;
1515
use LaravelJsonApi\Validation\Fields\IsValidated;
16-
use LaravelJsonApi\Validation\Fields\ValidatedWithKeyedSetOfRules;
16+
use LaravelJsonApi\Validation\Fields\ValidatedWithArrayKeys;
1717
use LaravelJsonApi\Validation\Rules\JsonArray;
18-
19-
use function is_null;
2018
use function sort;
2119

2220
class ArrayList extends Attribute implements IsValidated
2321
{
24-
use ValidatedWithKeyedSetOfRules;
22+
use ValidatedWithArrayKeys;
2523

2624
/**
2725
* @var bool
@@ -85,7 +83,7 @@ protected function deserialize($value)
8583
*/
8684
protected function assertValue($value): void
8785
{
88-
if ((!is_null($value) && !is_array($value)) || (!empty($value) && Arr::isAssoc($value))) {
86+
if (($value !== null && !is_array($value)) || (!empty($value) && Arr::isAssoc($value))) {
8987
throw new \UnexpectedValueException(sprintf(
9088
'Expecting the value of attribute %s to be an array list.',
9189
$this->name()

src/Fields/Boolean.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
namespace LaravelJsonApi\Eloquent\Fields;
1313

1414
use LaravelJsonApi\Validation\Fields\IsValidated;
15-
use LaravelJsonApi\Validation\Fields\ValidatedWithListOfRules;
15+
use LaravelJsonApi\Validation\Fields\ValidatedWithRules;
1616
use LaravelJsonApi\Validation\Rules\JsonBoolean;
1717

1818
class Boolean extends Attribute implements IsValidated
1919
{
20-
use ValidatedWithListOfRules;
20+
use ValidatedWithRules;
2121

2222
/**
2323
* Create a boolean attribute.

src/Fields/DateTime.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@
1212
namespace LaravelJsonApi\Eloquent\Fields;
1313

1414
use Carbon\CarbonInterface;
15-
use Closure;
1615
use Illuminate\Support\Facades\Date;
1716
use LaravelJsonApi\Validation\Fields\IsValidated;
18-
use LaravelJsonApi\Validation\Fields\ValidatedWithListOfRules;
17+
use LaravelJsonApi\Validation\Fields\ValidatedWithRules;
1918
use LaravelJsonApi\Validation\Rules\DateTimeIso8601;
2019
use function config;
2120

2221
class DateTime extends Attribute implements IsValidated
2322
{
24-
use ValidatedWithListOfRules;
23+
use ValidatedWithRules;
2524

2625
/**
2726
* Should dates be converted to the defined time zone?

src/Fields/Integer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
namespace LaravelJsonApi\Eloquent\Fields;
1313

1414
use LaravelJsonApi\Validation\Fields\IsValidated;
15-
use LaravelJsonApi\Validation\Fields\ValidatedWithListOfRules;
15+
use LaravelJsonApi\Validation\Fields\ValidatedWithRules;
1616
use LaravelJsonApi\Validation\Rules\JsonNumber;
1717
use UnexpectedValueException;
1818

1919
class Integer extends Attribute implements IsValidated
2020
{
21-
use ValidatedWithListOfRules;
21+
use ValidatedWithRules;
2222

2323
/**
2424
* @var bool

src/Fields/Number.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
namespace LaravelJsonApi\Eloquent\Fields;
1313

1414
use LaravelJsonApi\Validation\Fields\IsValidated;
15-
use LaravelJsonApi\Validation\Fields\ValidatedWithListOfRules;
15+
use LaravelJsonApi\Validation\Fields\ValidatedWithRules;
1616
use LaravelJsonApi\Validation\Rules\JsonNumber;
1717
use UnexpectedValueException;
1818

1919
class Number extends Attribute implements IsValidated
2020
{
21-
use ValidatedWithListOfRules;
21+
use ValidatedWithRules;
2222

2323
/**
2424
* @var bool

src/Fields/Relations/BelongsTo.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
use Illuminate\Database\Eloquent\Model;
1515
use LaravelJsonApi\Eloquent\Contracts\FillableToOne;
1616
use LaravelJsonApi\Eloquent\Fields\Concerns\IsReadOnly;
17+
use LaravelJsonApi\Validation\Fields\ValidatedWithArrayKeys;
18+
use LaravelJsonApi\Validation\Rules\HasOne as HasOneRule;
1719

1820
class BelongsTo extends ToOne implements FillableToOne
1921
{
2022
use IsReadOnly;
23+
use ValidatedWithArrayKeys;
2124

2225
/**
2326
* Create a belongs-to relation.
@@ -93,4 +96,12 @@ public function associate(Model $model, ?array $identifier): ?Model
9396

9497
return $model->getRelation($this->relationName());
9598
}
99+
100+
/**
101+
* @return array
102+
*/
103+
protected function defaultRules(): array
104+
{
105+
return ['.' => ['array:type,id', new HasOneRule($this)]];
106+
}
96107
}

src/Fields/Relations/BelongsToMany.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,22 @@
1111

1212
namespace LaravelJsonApi\Eloquent\Fields\Relations;
1313

14+
use Closure;
1415
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
1516
use Illuminate\Database\Eloquent\Model;
1617
use Illuminate\Database\Eloquent\Relations\BelongsToMany as EloquentBelongsToMany;
1718
use InvalidArgumentException;
1819
use LaravelJsonApi\Eloquent\Contracts\FillableToMany;
1920
use LaravelJsonApi\Eloquent\Fields\Concerns\IsReadOnly;
21+
use LaravelJsonApi\Validation\Fields\ValidatedWithArrayKeys;
22+
use LaravelJsonApi\Validation\Rules\HasMany as HasManyRule;
23+
use LaravelJsonApi\Validation\Rules\JsonArray;
2024
use function sprintf;
2125

2226
class BelongsToMany extends ToMany implements FillableToMany
2327
{
24-
2528
use IsReadOnly;
29+
use ValidatedWithArrayKeys;
2630

2731
/**
2832
* Create a belongs-to-many relation.
@@ -142,6 +146,17 @@ public function detach(Model $model, array $identifiers): iterable
142146
return $related;
143147
}
144148

149+
/**
150+
* @return array
151+
*/
152+
protected function defaultRules(): array
153+
{
154+
return [
155+
'.' => [new JsonArray(), new HasManyRule($this)],
156+
'*' => ['array:type,id'],
157+
];
158+
}
159+
145160
/**
146161
* @param Model $model
147162
* @return EloquentBelongsToMany

src/Fields/Relations/HasMany.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
use Illuminate\Database\Eloquent\Relations\MorphMany as EloquentMorphMany;
1818
use LaravelJsonApi\Eloquent\Contracts\FillableToMany;
1919
use LaravelJsonApi\Eloquent\Fields\Concerns\IsReadOnly;
20+
use LaravelJsonApi\Validation\Fields\ValidatedWithArrayKeys;
21+
use LaravelJsonApi\Validation\Rules\HasMany as HasManyRule;
22+
use LaravelJsonApi\Validation\Rules\JsonArray;
2023
use function sprintf;
2124

2225
class HasMany extends ToMany implements FillableToMany
@@ -31,6 +34,7 @@ class HasMany extends ToMany implements FillableToMany
3134
private const FORCE_DELETE_DETACHED_MODELS = 2;
3235

3336
use IsReadOnly;
37+
use ValidatedWithArrayKeys;
3438

3539
/**
3640
* Flag for how to detach models from the relationship.
@@ -134,6 +138,17 @@ public function detach(Model $model, array $identifiers): iterable
134138
return $models;
135139
}
136140

141+
/**
142+
* @return array
143+
*/
144+
protected function defaultRules(): array
145+
{
146+
return [
147+
'.' => [new JsonArray(), new HasManyRule($this)],
148+
'*' => ['array:type,id'],
149+
];
150+
}
151+
137152
/**
138153
* @param Model $model
139154
* @param EloquentCollection $new

src/Fields/Relations/HasOne.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616
use Illuminate\Database\Eloquent\Relations\MorphOne as EloquentMorphOne;
1717
use LaravelJsonApi\Eloquent\Contracts\FillableToOne;
1818
use LaravelJsonApi\Eloquent\Fields\Concerns\IsReadOnly;
19+
use LaravelJsonApi\Validation\Fields\ValidatedWithArrayKeys;
20+
use LaravelJsonApi\Validation\Rules\HasOne as HasOneRule;
1921

2022
class HasOne extends ToOne implements FillableToOne
2123
{
24+
use ValidatedWithArrayKeys;
25+
2226
/** @var int */
2327
private const KEEP_DETACHED_MODEL = 0;
2428

@@ -135,6 +139,14 @@ public function associate(Model $model, ?array $identifier): ?Model
135139
return $model->getRelation($this->relationName());
136140
}
137141

142+
/**
143+
* @return array
144+
*/
145+
protected function defaultRules(): array
146+
{
147+
return ['.' => ['array:type,id', new HasOneRule($this)]];
148+
}
149+
138150
/**
139151
* @param Model|null $current
140152
* @param Model|null $new

src/Fields/Relations/MorphToMany.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
use LaravelJsonApi\Eloquent\Fields\Concerns\IsReadOnly;
2424
use LaravelJsonApi\Eloquent\Polymorphism\MorphMany;
2525
use LaravelJsonApi\Eloquent\Polymorphism\MorphValue;
26+
use LaravelJsonApi\Validation\Fields\ValidatedWithArrayKeys;
27+
use LaravelJsonApi\Validation\Rules\HasMany as HasManyRule;
28+
use LaravelJsonApi\Validation\Rules\JsonArray;
2629
use LogicException;
2730
use Traversable;
2831
use UnexpectedValueException;
@@ -31,6 +34,7 @@ class MorphToMany extends ToMany implements PolymorphicRelation, IteratorAggrega
3134
{
3235
use Polymorphic;
3336
use IsReadOnly;
37+
use ValidatedWithArrayKeys;
3438

3539
/**
3640
* @var array
@@ -240,6 +244,17 @@ public function parse($models): iterable
240244
throw new LogicException('Expecting model value to already be a morph many value.');
241245
}
242246

247+
/**
248+
* @return array
249+
*/
250+
protected function defaultRules(): array
251+
{
252+
return [
253+
'.' => [new JsonArray(), new HasManyRule($this)],
254+
'*' => ['array:type,id'],
255+
];
256+
}
257+
243258
/**
244259
* Get the identifiers that are valid for the supplied relation.
245260
*

src/Fields/Relations/Relation.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535

3636
abstract class Relation implements RelationContract, SchemaAwareContract, SerializableContract
3737
{
38-
3938
use EagerLoadable;
4039
use Filterable;
4140
use Hideable;

src/Fields/Str.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
namespace LaravelJsonApi\Eloquent\Fields;
1313

1414
use LaravelJsonApi\Validation\Fields\IsValidated;
15-
use LaravelJsonApi\Validation\Fields\ValidatedWithListOfRules;
15+
use LaravelJsonApi\Validation\Fields\ValidatedWithRules;
1616

1717
class Str extends Attribute implements IsValidated
1818
{
19-
use ValidatedWithListOfRules;
19+
use ValidatedWithRules;
2020

2121
/**
2222
* Create a string attribute.

tests/lib/Integration/Fields/ArrayHashTest.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -576,19 +576,28 @@ public function testHiddenCallback(): void
576576

577577
public function testIsValidated(): void
578578
{
579-
$attr = ArrayHash::make('permissions');
579+
$attr = ArrayHash::make('permissions')
580+
->creationRules(['.' => 'array:foo,bar'])
581+
->updateRules(['.' => 'array:foo,bar']);
582+
583+
$expected = [
584+
'.' => [new JsonObject(), 'array:foo,bar'],
585+
];
580586

581587
$this->assertInstanceOf(IsValidated::class, $attr);
582-
$this->assertEquals($expected = ['.' => new JsonObject()], $attr->rulesForCreation(null));
588+
$this->assertEquals($expected, $attr->rulesForCreation(null));
583589
$this->assertEquals($expected, $attr->rulesForUpdate(null, new \stdClass()));
584590
}
585591

586592
public function testIsValidatedAndAllowsEmpty(): void
587593
{
588-
$attr = ArrayHash::make('permissions')->allowEmpty();
594+
$attr = ArrayHash::make('permissions')
595+
->allowEmpty()
596+
->creationRules(['.' => 'array:foo,bar'])
597+
->updateRules(['.' => 'array:foo,bar']);
589598

590599
$this->assertEquals(
591-
$expected = ['.' => (new JsonObject())->allowEmpty()],
600+
$expected = ['.' => [(new JsonObject())->allowEmpty(), 'array:foo,bar']],
592601
$attr->rulesForCreation(null)
593602
);
594603
$this->assertEquals($expected, $attr->rulesForUpdate(null, new \stdClass()));

tests/lib/Integration/Fields/ArrayListTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ public function testItIsValidated(): void
334334
$attr = ArrayList::make('permissions');
335335

336336
$this->assertInstanceOf(IsValidated::class, $attr);
337-
$this->assertEquals($expected = ['.' => new JsonArray()], $attr->rulesForCreation(null));
337+
$this->assertEquals($expected = ['.' => [new JsonArray()]], $attr->rulesForCreation(null));
338338
$this->assertEquals($expected, $attr->rulesForUpdate(null, new \stdClass()));
339339
}
340340
}

0 commit comments

Comments
 (0)