Drupal FAPI drupal_array_set_nested_value 錯誤

Drupal FAPI drupal_array_set_nested_value 錯誤

情境

bug everywhere

有時候我們總需要使用 hook_form_alter 將現有的 form elements 進行一些改變或是增加欄位 ,所以我新增了一個自訂的 AJAX 讓它 return 一個 from 給我,可是只要當前頁面 return 兩次以上,或是當前的 form 有錯誤並且再按送出就會有以下的錯誤
Warning:Illegal string offset 'und' at drupal_array_set_nested_value()
Error:Cannot create references to/from string offsets nor overloaded objects at drupal_array_set_nested_value()

這個錯誤,並不是我程式寫錯而是東西丟給 drupal 核心內的錯誤,更是提高了 debug 的難度阿。

開始漫長的 debug 之路

function MYMODULE_form_commerce_checkout_form_alter(&$form, &$form_state, $form_id){
                // Add the form element for selecting a saved address.
                $form[$pane_id]['my_save_profile_options'] = array(
                  '#type' => 'radios',
                  '#title' => t('My Addressbook'),
                  '#options' => MYMODULE_options($profiles),
                  '#weight' => -100,
                  '#ajax' => array(
                    'callback' => 'MYMODULE_form_refresh',
                    'wrapper' => 'customer-profile-' . $key . '-ajax-wrapper',
                    'method'=>'replace',
                  ),
                );
}

function MYMODULE_form_refresh($form, &$form_state)
{

    $pane_id = $form_state['triggering_element']['#parents'][0];
    $profile_id=$form_state['values']['customer_profile_recipient']['my_save_profile_options'];

    $profile=commerce_customer_profile_load($profile_id);
    // Add replace element as default AJAX command.
    $form['customer_profile_recipient']['field_billing_name']['und'][0]['value']['#value']=$profile->field_billing_name['und'][0]['value'];
    $form['customer_profile_recipient']['field_billing_phone']['und'][0]['value']['#value']=$profile->field_billing_phone['und'][0]['value'];
    $form['customer_profile_recipient']['field_billing_address']['und'][0]['value']['#value']=$profile->field_billing_address['und'][0]['value'];
    $form['customer_profile_recipient']['my_save_profile_options'][$profile_id]['#value']=null;

    return $form['customer_profile_recipient'];
}

最後最後發覺問題是在 return $form['customer_profile_recipient']; 這行,只要我 return $form['customer_profile_recipient']; 就會錯誤,只好去看一下 drupal_array_set_nested_value

drupal_array_set_nested_value(array &$array, array $parents, $value, $force = FALSE) 讓我們看到最後一個參數 $force

$force: (Optional) If TRUE, the value is forced into the structure even if it requires the deletion of an already existing non-array parent value. If FALSE, PHP throws an error if trying to add into a value that is not an array. Defaults to FALSE.

所以我們可以得知 form submit 有使用這個 function 來做一些事情,可是問題出在那呢?意思就是當我進到資料庫,你給我的東西不符合我的格式我就會噴錯誤給你,如果設定為 TRUE 就會轉換成相容的格式
舉個例子:我要的可能是字串可是你給我的是陣列

也是有人在討論這個 issues 如 Cannot create references to/from string offsets nor overloaded objects 也有寫了一個 patch 去更改預設為 TRUE 就解決了以上的問題了,打 patch 去更改核心的 code 不是很安全,久了忘了一更新就炸了,特別在此紀錄一下。