2011-03-07 6 views
2

最近、私はEntity APIを使用してDrupal 7モジュールを構築していましたが、問題が発生しました。編集フォームをデバッグすると、loadメソッドが2回呼び出され、エラーが発生していることに気付きました。エンティティメソッドを2回ロードする

Recoverable fatal error: Object of class stdClass could not be converted to string in DatabaseStatementBase->execute() (regel 2039 van /drupal7/includes/database/database.inc).

これはFooController :: loadが2回実行されたために発生します。

下のコードは、私が使っているコードです。

function foo_menu() { 
    $items = array(); 
    ... 
    $items['admin/foo/%foo/edit'] = array(
    'title' => 'Edit foo', 
    'page callback' => 'foo_edit', 
    'page arguments' => array(2), 
    'access arguments' => array('administer content'), 
    'type' => MENU_CALLBACK, 
); 
    ... 
    return $items; 
} 

function foo_edit($foo) { 
    return drupal_get_form('foo_edit_form', $foo); 
} 

function foo_edit_form($form, &$form_state, $foo) { 
    $form['#foo'] = $foo; 
    $form_state['values'] = $foo; 

    $form['id'] = array(
    '#type' => 'hidden', 
    '#value' => $foo->id, 
); 
    ... 
    $form['picture'] = array(
    '#type' => 'file', 
    '#title' => t('Picture'), 
    '#default_value' => $foo->picture->filename, 
); 
    ... 
    $form['submit'] = array(
    '#type' => 'submit', 
    '#value' => t('Save'), 
); 

    return $form; 
} 

function foo_edit_form_submit($form, &$form_state) { 
    $foo = (object)$form_state['values']; 

    if ($picture = file_save_upload('picture')) { 
    $picture = file_move($picture, FOO_FILE_PATH . $picture->filename, FILE_EXISTS_RENAME); 
    $picture->status |= FILE_STATUS_PERMANENT; 
    $picture = file_save($picture);  
    $foo->picture = $picture->fid; 
    } 

    entity_get_controller('foo')->save($foo); 

    drupal_set_message(t('Foo saved.')); 
    $form_state['redirect'] = 'admin/foo'; 
} 

そしておそらく最も重要な部分:

function foo_load ($id) { 
    $foo = foo_load_multiple(array($id)); 
    return $foo ? $foo[$id] : FALSE; 
} 
function foo_load_multiple ($ids = array(), $conditions = array()) { 
    return entity_load('foo', $ids, $conditions); 
} 
class FooController extends DrupalDefaultEntityController { 
    ...  
    function load ($ids = array(), $conditions = array()) { 
    $foos = parent::load($ids, $conditions); 

    // Code executed twice 
    error_log('FooController::load'); 

    foreach ($foos as $foo) { 
     $foo->picture = file_load($foo->picture); 
    } 
    return $foos; 
    } 
    ... 
} 

編集:コールスタック

... (Array, 11 elements) 
    11: load (Array, 7 elements) 
    10: entity_load (Array, 4 elements) 
    9: foo_load_multiple (Array, 4 elements) 
    8: foo_load (Array, 4 elements) 
    7: _menu_load_objects (Array, 4 elements) 
    6: _menu_translate (Array, 4 elements) 
    5: menu_get_item (Array, 4 elements) 
    4: menu_get_custom_theme (Array, 4 elements) 
    3: menu_set_custom_theme (Array, 4 elements) 
    2: _drupal_bootstrap_full (Array, 4 elements) 
    1: drupal_bootstrap (Array, 4 elements) 
Called from /sites/bar/modules/custom/foo/foo.module, line 367 

... (Array, 20 elements) 
    20: load (Array, 7 elements) 
    19: entity_load (Array, 4 elements) 
    18: foo_load_multiple (Array, 4 elements) 
    17: foo_load (Array, 4 elements) 
    16: _menu_load_objects (Array, 4 elements) 
    15: _menu_translate (Array, 4 elements) 
    14: menu_local_tasks (Array, 4 elements) 
    13: menu_tab_root_path (Array, 4 elements) 
    12: menu_get_active_help (Array, 4 elements) 
    11: system_block_view (Array, 2 elements) 
    10: call_user_func_array (Array, 4 elements) 
    9: module_invoke (Array, 4 elements) 
    8: _block_render_blocks (Array, 4 elements) 
    7: block_list (Array, 4 elements) 
    6: block_get_blocks_by_region (Array, 4 elements) 
    5: block_page_build (Array, 4 elements) 
    4: drupal_render_page (Array, 4 elements) 
    3: drupal_deliver_html_page (Array, 4 elements) 
    2: drupal_deliver_page (Array, 4 elements) 
    1: menu_execute_active_handler (Array, 4 elements) 
Called from /sites/bar/modules/custom/foo/foo.module, line 367 

は誰も前にこの問題を経験していますか?

ありがとうございます。

ソリューション(@Berdirのおかげで):

代わりのオーバーライドDrupalDefaultEntityController ::負荷()、attachLoadを使用しては():2番目の呼び出しは、実際にあるよう

protected function attachLoad(&$foos, $revision_id = FALSE) { 
    foreach ($foos as $foo) { 
     $foo->picture = file_load($foo->picture); 
    } 
    parent::attachLoad($foos, $revision_id); 
    } 

答えて

2

それは私には見えます無効なもの(int/stringの代わりにオブジェクト)を渡します。

error_log()コールの代わりに "debug_print_backtrace()"を実行するか、devel.moduleがインストールされている場合は "ddebug_backtrace()"を実行してください。それはあなたがいつ正確にあなたのロード関数を呼び出しているのかを知るコールスタックを与えます。最初のコマンドは多くの生のテキストを出力し、2番目のコマンドは読みやすい方法です。

: load()メソッドをオーバーライドする代わりに、attachLoad()を実装する必要があります。これは、新しく読み込まれたエンティティに対して1回だけ呼び出されます。例については、http://api.worldempire.ch/api/privatemsg/privatemsg.module/function/PrivatemsgMessageController::attachLoad/7-1を参照してください。

+0

コールスタックを追加しました! – Bart

+1

私はこれも既に闘っていたデフォルトの行動だと思います。メニューオブジェクトはメニューのために1回ロードされ、ヘルプシステムを得るために1回ロードされます。しかし、エンティティは、とにかく静的にキャッシュされ、foo_load()を複数回呼び出すことをサポートする必要があります。ですから問題はあなたのfile_load()行です。それが既にロードされている場合、これはあなたが終わるものです。私はそれを修正する方法で私の答えを更新します。 – Berdir

+0

私は現時点でquickfixを使用していますが、明らかに私はむしろそれを使用しません。 file_load(string)は、最初のload()にすでに挿入されているオブジェクトをロードしようとしているため、2番目のload()でエラーを引き起こしています。 2番目のload()では、ピクチャオブジェクトがすでにfooオブジェクトに挿入されていることが不思議に思えます。 parent :: loadのデータベースから選択されると思いますが、何とか最初のload()(キャッシング?)にロードされたオブジェクトを使用しています。エンティティapiのドキュメントが不足していると、どちらも役に立ちません。 – Bart