@@ -207,6 +207,12 @@ private function getAllFieldsIncludingBuilderFields(array $builderBlocks): Colle
207207 private function applyFieldFillMutation (Model $ field , array $ fieldConfig , object $ fieldInstance , array $ data , array $ builderBlocks ): array
208208 {
209209 if (! empty ($ fieldConfig ['methods ' ]['mutateFormDataCallback ' ])) {
210+ $ fieldLocation = $ this ->determineFieldLocation ($ field , $ builderBlocks );
211+
212+ if ($ fieldLocation ['isInBuilder ' ]) {
213+ return $ this ->processBuilderFieldFillMutation ($ field , $ fieldInstance , $ data , $ fieldLocation ['builderData ' ], $ builderBlocks );
214+ }
215+
210216 return $ fieldInstance ->mutateFormDataCallback ($ this ->record , $ field , $ data );
211217 }
212218
@@ -217,67 +223,28 @@ private function applyFieldFillMutation(Model $field, array $fieldConfig, object
217223 }
218224
219225 /**
220- * Apply field-specific mutation logic for form saving.
221- *
222- * This method handles both regular fields and fields within builder blocks.
223- * Builder blocks require special processing because they contain nested data structures.
226+ * Extract builder blocks from record values.
224227 *
225- * @param Model $field The field model
226- * @param array $fieldConfig The field configuration
227- * @param object $fieldInstance The field instance
228- * @param array $data The form data
229- * @param array $builderBlocks The builder blocks
230- * @return array The mutated data
228+ * @return array The builder blocks
231229 */
232- private function applyFieldSaveMutation ( Model $ field , array $ fieldConfig , object $ fieldInstance , array $ data , array $ builderBlocks ): array
230+ private function extractBuilderBlocksFromRecord ( ): array
233231 {
234- if (empty ($ fieldConfig ['methods ' ]['mutateBeforeSaveCallback ' ])) {
235- return $ data ;
236- }
237-
238- $ fieldLocation = $ this ->determineFieldLocation ($ field , $ builderBlocks );
239-
240- if ($ fieldLocation ['isInBuilder ' ]) {
241- return $ this ->processBuilderFieldMutation ($ field , $ fieldInstance , $ data , $ fieldLocation ['builderData ' ], $ builderBlocks );
232+ if (!isset ($ this ->record ->values ) || !is_array ($ this ->record ->values )) {
233+ return [];
242234 }
243235
244- // Regular field processing
245- return $ fieldInstance ->mutateBeforeSaveCallback ($ this ->record , $ field , $ data );
246- }
247-
248- /**
249- * Determine if a field is inside a builder block and extract its data.
250- *
251- * @param Model $field The field to check
252- * @param array $builderBlocks The builder blocks
253- * @return array Location information with 'isInBuilder' and 'builderData' keys
254- */
255- private function determineFieldLocation (Model $ field , array $ builderBlocks ): array
256- {
257- foreach ($ builderBlocks as $ builderUlid => $ builderBlocks ) {
258- if (is_array ($ builderBlocks )) {
259- foreach ($ builderBlocks as $ block ) {
260- if (isset ($ block ['data ' ]) && is_array ($ block ['data ' ]) && isset ($ block ['data ' ][$ field ->ulid ])) {
261- return [
262- 'isInBuilder ' => true ,
263- 'builderData ' => $ block ['data ' ],
264- ];
265- }
266- }
267- }
268- }
236+ $ builderFieldUlids = ModelsField::whereIn ('ulid ' , array_keys ($ this ->record ->values ))
237+ ->where ('field_type ' , 'builder ' )
238+ ->pluck ('ulid ' )
239+ ->toArray ();
269240
270- return [
271- 'isInBuilder ' => false ,
272- 'builderData ' => null ,
273- ];
241+ return collect ($ this ->record ->values )
242+ ->filter (fn ($ value , $ key ) => in_array ($ key , $ builderFieldUlids ))
243+ ->toArray ();
274244 }
275245
276246 /**
277- * Process mutation for fields inside builder blocks.
278- *
279- * Builder fields require special handling because they're nested within
280- * a complex data structure that needs to be updated in place.
247+ * Process fill mutation for fields inside builder blocks.
281248 *
282249 * @param Model $field The field model
283250 * @param object $fieldInstance The field instance
@@ -286,14 +253,14 @@ private function determineFieldLocation(Model $field, array $builderBlocks): arr
286253 * @param array $builderBlocks All builder blocks
287254 * @return array The updated form data
288255 */
289- private function processBuilderFieldMutation (Model $ field , object $ fieldInstance , array $ data , array $ builderData , array $ builderBlocks ): array
256+ private function processBuilderFieldFillMutation (Model $ field , object $ fieldInstance , array $ data , array $ builderData , array $ builderBlocks ): array
290257 {
291258 // Create a mock record with the builder data for the callback
292259 $ mockRecord = $ this ->createMockRecordForBuilder ($ builderData );
293260
294261 // Create a temporary data structure for the callback
295262 $ tempData = [$ this ->record ->valueColumn => $ builderData ];
296- $ tempData = $ fieldInstance ->mutateBeforeSaveCallback ($ mockRecord , $ field , $ tempData );
263+ $ tempData = $ fieldInstance ->mutateFormDataCallback ($ mockRecord , $ field , $ tempData );
297264
298265 // Update the original data structure with the mutated values
299266 $ this ->updateBuilderBlocksWithMutatedData ($ builderBlocks , $ field , $ tempData );
@@ -513,4 +480,92 @@ private function generateInputName(Model $field, mixed $record, bool $isNested):
513480 {
514481 return $ isNested ? "{$ field ->ulid }" : "{$ record ->valueColumn }. {$ field ->ulid }" ;
515482 }
483+
484+ /**
485+ * Apply field-specific mutation logic for form saving.
486+ *
487+ * This method handles both regular fields and fields within builder blocks.
488+ * Builder blocks require special processing because they contain nested data structures.
489+ *
490+ * @param Model $field The field model
491+ * @param array $fieldConfig The field configuration
492+ * @param object $fieldInstance The field instance
493+ * @param array $data The form data
494+ * @param array $builderBlocks The builder blocks
495+ * @return array The mutated data
496+ */
497+ private function applyFieldSaveMutation (Model $ field , array $ fieldConfig , object $ fieldInstance , array $ data , array $ builderBlocks ): array
498+ {
499+ if (empty ($ fieldConfig ['methods ' ]['mutateBeforeSaveCallback ' ])) {
500+ return $ data ;
501+ }
502+
503+ $ fieldLocation = $ this ->determineFieldLocation ($ field , $ builderBlocks );
504+
505+ if ($ fieldLocation ['isInBuilder ' ]) {
506+ return $ this ->processBuilderFieldMutation ($ field , $ fieldInstance , $ data , $ fieldLocation ['builderData ' ], $ builderBlocks );
507+ }
508+
509+ // Regular field processing
510+ return $ fieldInstance ->mutateBeforeSaveCallback ($ this ->record , $ field , $ data );
511+ }
512+
513+ /**
514+ * Determine if a field is inside a builder block and extract its data.
515+ *
516+ * @param Model $field The field to check
517+ * @param array $builderBlocks The builder blocks
518+ * @return array Location information with 'isInBuilder' and 'builderData' keys
519+ */
520+ private function determineFieldLocation (Model $ field , array $ builderBlocks ): array
521+ {
522+ foreach ($ builderBlocks as $ builderUlid => $ builderBlocks ) {
523+ if (is_array ($ builderBlocks )) {
524+ foreach ($ builderBlocks as $ block ) {
525+ if (isset ($ block ['data ' ]) && is_array ($ block ['data ' ]) && isset ($ block ['data ' ][$ field ->ulid ])) {
526+ return [
527+ 'isInBuilder ' => true ,
528+ 'builderData ' => $ block ['data ' ],
529+ ];
530+ }
531+ }
532+ }
533+ }
534+
535+ return [
536+ 'isInBuilder ' => false ,
537+ 'builderData ' => null ,
538+ ];
539+ }
540+
541+ /**
542+ * Process mutation for fields inside builder blocks.
543+ *
544+ * Builder fields require special handling because they're nested within
545+ * a complex data structure that needs to be updated in place.
546+ *
547+ * @param Model $field The field model
548+ * @param object $fieldInstance The field instance
549+ * @param array $data The form data
550+ * @param array $builderData The builder block data
551+ * @param array $builderBlocks All builder blocks
552+ * @return array The updated form data
553+ */
554+ private function processBuilderFieldMutation (Model $ field , object $ fieldInstance , array $ data , array $ builderData , array $ builderBlocks ): array
555+ {
556+ // Create a mock record with the builder data for the callback
557+ $ mockRecord = $ this ->createMockRecordForBuilder ($ builderData );
558+
559+ // Create a temporary data structure for the callback
560+ $ tempData = [$ this ->record ->valueColumn => $ builderData ];
561+ $ tempData = $ fieldInstance ->mutateBeforeSaveCallback ($ mockRecord , $ field , $ tempData );
562+
563+ // Update the original data structure with the mutated values
564+ $ this ->updateBuilderBlocksWithMutatedData ($ builderBlocks , $ field , $ tempData );
565+
566+ // Update the main data structure
567+ $ data [$ this ->record ->valueColumn ] = array_merge ($ data [$ this ->record ->valueColumn ], $ builderBlocks );
568+
569+ return $ data ;
570+ }
516571}
0 commit comments