2011-03-07 3 views
2

최근에 Entity API를 사용하여 Drupal 7 모듈을 작성했지만 문제가 발생했습니다. 편집 폼을 디버깅 할 때 load 메서드가 두 번 호출되어 오류를 일으키는 것으로 나타났습니다.엔터티 메서드 두 번로드

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가 두 번 실행되기 때문에 발생합니다.

아래 코드는 내가 사용 해본 코드입니다.

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 덕분에) :

대신 오버라이드 (override) DrupalDefaultEntityController :: 부하(), attachLoad를 사용하여가() : 두 번째 호출은 실제로 같은

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()"를 실행하십시오. 그러면 콜 스택 (callstack)을 통해 정확히 누가로드 기능을 호출하는지 알 수 있습니다. 첫 번째 명령은 원시 텍스트를 많이 인쇄하고 두 번째 명령은 읽기 쉬운 방법입니다.

편집 : load() 메서드를 재정의하는 대신 attachLoad()를 대신 구현해야합니다. 이것은 새로로드 된 엔티티에 대해서만 한 번 호출됩니다. 예를 들어 http://api.worldempire.ch/api/privatemsg/privatemsg.module/function/PrivatemsgMessageController::attachLoad/7-1을 참조하십시오.

+0

호출 스택 추가! – Bart

+1

나는 이것이 이미 너무 싸워야 만하는 기본 행동이라고 생각합니다. 메뉴 객체는 메뉴에 대해 한 번로드되고 도움말 시스템을 얻기 위해 한 번로드됩니다. 그러나 엔티티는 어쨌든 정적으로 캐시되어야하고 foo_load()를 여러 번 호출해야합니다. 그래서 문제는 file_load() 라인입니다. 이미로드되어 있다면, 이것이 결국 끝내게됩니다. 나는 그것을 해결할 수있는 방법으로 나의 대답을 업데이트 할 것이다. – Berdir

+0

현재 퀵 픽스를 사용하고 있지만 분명히 사용하지는 않을 것입니다. file_load (string)는 첫 번째 load()에 이미 삽입 된 객체를로드하려고하기 때문에 두 번째 load()에서 오류를 발생시킵니다. 두 번째 load()에서 그림 객체가 foo 객체에 이미 삽입되었다는 이상한 것처럼 보입니다. parent :: load의 데이터베이스에서 선택 하겠지만, 어떻게 든 첫 번째 load() (캐싱?)에로드 된 객체를 사용하고 있다고 생각할 수 있습니다. 엔티티 API에 대한 문서가 부족하여도 도움이되지 않습니다. :). – Bart

관련 문제