@@ -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 ();
0 commit comments