Skip to content

Commit 9b44f9d

Browse files
committed
validate supported write relations
1 parent acbea24 commit 9b44f9d

File tree

4 files changed

+66
-6
lines changed

4 files changed

+66
-6
lines changed

src/Exceptions/NestedModelException.php

+5
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,9 @@ public static function forIncorrectReturnType(string $name): static
3232
{
3333
return new self(lang('NestedModel.incorrectReturnType', [$name]));
3434
}
35+
36+
public static function forRelationDoesNotSupportWrite(): static
37+
{
38+
return new self(lang('NestedModel.relationDoesNotSupportWrite'));
39+
}
3540
}

src/Language/en/NestedModel.php

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<?php
22

33
return [
4-
'methodNotSupported' => 'This method is not supported for the "{0}" relation.',
5-
'parentRelationNotDeclared' => 'Parent relation "{0}" has not been declared yet.',
6-
'relationNotDefined' => 'Relation "{0}" is not defined.',
7-
'missingReturnType' => 'Method "{0}()" is missing a required return type declaration.',
8-
'incorrectReturnType' => 'Method "{0}()" returned an incorrect type.',
4+
'methodNotSupported' => 'This method is not supported for the "{0}" relation.',
5+
'parentRelationNotDeclared' => 'Parent relation "{0}" has not been declared yet.',
6+
'relationNotDefined' => 'Relation "{0}" is not defined.',
7+
'missingReturnType' => 'Method "{0}()" is missing a required return type declaration.',
8+
'incorrectReturnType' => 'Method "{0}()" returned an incorrect type.',
9+
'relationDoesNotSupportWrite' => 'This type of relation does not support write.',
910
];

src/Traits/HasRelations.php

+47-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ protected function initRelations(): void
3939
helper('inflector');
4040
}
4141

42+
/**
43+
* Set the relation to use.
44+
*/
4245
public function with(string $relation, ?Closure $closure = null): static
4346
{
4447
if (str_contains($relation, '.')) {
@@ -64,6 +67,9 @@ public function with(string $relation, ?Closure $closure = null): static
6467
return $this;
6568
}
6669

70+
/**
71+
* Validate relation definition.
72+
*/
6773
private function checkReturnType(string $methodName): bool
6874
{
6975
if (! method_exists($this, $methodName)) {
@@ -183,12 +189,18 @@ public function belongsToMany(Model|string $model, ?string $pivotTable = null, ?
183189
->setMany($pivotTable, $pivotForeignKey, $pivotRelatedKey);
184190
}
185191

192+
/**
193+
* Return model instance.
194+
*/
186195
private function getModelInstance(Model|string $model): Model
187196
{
188197
return $model instanceof Model ? $model : model($model);
189198
}
190199

191-
private function createPivotTableName($table1, $table2): string
200+
/**
201+
* Create pivot table name.
202+
*/
203+
private function createPivotTableName(mixed $table1, mixed $table2): string
192204
{
193205
$tables = [$table1, $table2];
194206
sort($tables);
@@ -199,6 +211,8 @@ private function createPivotTableName($table1, $table2): string
199211
}
200212

201213
/**
214+
* Get the caller method name.
215+
*
202216
* @throws ReflectionException
203217
*/
204218
private function getInitialMethodName(): string
@@ -378,6 +392,9 @@ protected function relationsAfterFind(array $eventData): array
378392
return $eventData;
379393
}
380394

395+
/**
396+
* Get relation data for a single item.
397+
*/
381398
protected function getDataForRelationById(int|string $id, Relation $relation)
382399
{
383400
$relation->applyWith()->applyRelation([$id], $this->primaryKey)->applyConditions();
@@ -389,6 +406,9 @@ protected function getDataForRelationById(int|string $id, Relation $relation)
389406
return $relation->filterResults($results, $this->tempReturnType);
390407
}
391408

409+
/**
410+
* Get relation data for many items.
411+
*/
392412
protected function getDataForRelationByIds(array $id, Relation $relation): array
393413
{
394414
$relation->applyWith()->applyRelation($id, $this->primaryKey)->applyConditions();
@@ -439,6 +459,28 @@ protected function getDataForRelationByIds(array $id, Relation $relation): array
439459
return $relationData;
440460
}
441461

462+
/**
463+
* Validate if given relation can be handled during write operation.
464+
*/
465+
protected function validateWriteRelations(): void
466+
{
467+
if ($this->relations === []) {
468+
return;
469+
}
470+
471+
foreach ($this->relations as $relation) {
472+
if (
473+
! in_array($relation->type, [RelationTypes::hasOne, RelationTypes::hasMany], true)
474+
|| (
475+
in_array($relation->type, [RelationTypes::hasOne, RelationTypes::hasMany], true)
476+
&& ($relation->hasMany() || $relation->hasThrough())
477+
)
478+
) {
479+
throw NestedModelException::forRelationDoesNotSupportWrite();
480+
}
481+
}
482+
}
483+
442484
/**
443485
* Whether to use transaction during insert/update.
444486
*/
@@ -451,6 +493,8 @@ public function useTransactions(bool $value = true): static
451493

452494
public function insert($row = null, bool $returnID = true): bool|int|string
453495
{
496+
$this->validateWriteRelations();
497+
454498
if ($this->useTransactions) {
455499
try {
456500
$this->db->transException(true)->transStart();
@@ -480,6 +524,8 @@ public function insert($row = null, bool $returnID = true): bool|int|string
480524

481525
public function update($id = null, $row = null): bool
482526
{
527+
$this->validateWriteRelations();
528+
483529
if ($this->useTransactions) {
484530
try {
485531
$this->db->transException(true)->transStart();

tests/ExceptionTest.php

+8
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,12 @@ public function testMethodNotSupported(): void
6060

6161
model(UserModel::class)->posts()->latestOfMany();
6262
}
63+
64+
public function testNotValidWriteRelation(): void
65+
{
66+
$this->expectException(NestedModelException::class);
67+
$this->expectExceptionMessage('This type of relation does not support write.');
68+
69+
model(UserModel::class)->with('address')->insert(['what' => 'ever']);
70+
}
6371
}

0 commit comments

Comments
 (0)