Drupal7中自定义表格输入

Drupal默认的节点表单(entity form)输入有时候并不能满足我们的需求,比如我想做一个类似excel表格输入形式的表单呢?

  • = DEMO点这里 (PS. 用Pantheon的sandbox做了一个随意折腾的drupal站点,真的是折腾死我了= =)

首先,新建一个自定义模块,在你的*.module文件中hook_menu() 指定一个页面路径,设置页面调用表单,比如这样:

function demo_tableform_menu(){  
    $items = array();
    $items['demo/theme_table_into_form'] = array(
        'title callback' => '表格方式輸入表單',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('classroomtable_form'),
        'access callback' => TRUE,
    );

    return $items;
}

然后hook_form()把这个表格的基本元素写出来,用#header标签设置表格的表头部分,填充表格的每一行就用#rows标签,表单元素常见的input name用#name表示,标签#theme是用来设置之后如何渲染这个表单的,最后用$form['submit']设置表单提交后的动作。这整段的代码可以写成这样:

function classroomtable_form($form, &$form_state){  
    $header = array(
        'sex'=>'性別',
        'number'=>'人數',
        'height'=>'平均身高',
        'classroom'=>'班級',
    );
    $options = array();
    $options[] = array(
        'sex' =>array(
            'data' =>array(
                '#type'=>'select',
                '#name'=>'sex',
                '#options'=>array(
                    'F'=>'女',
                    'M'=>'男'
                ),
            ),
        ),
        'number'=>array(
            'data'=>array(
                '#type'=>'textfield',
                '#name'=>'number',
                '#attributes'=>array(
                    'placeholder' => 0,
                ),
                '#size'=>12,
            ),
        ),
        'height'=>array(
            'data'=>array(
                '#type'=>'textfield',
                '#name' => 'height',
                '#attributes' => array(
                    'placeholder' => 0,
                ),
                '#size'=>12,
            ),
        ),
        'classroom'=>array(
            'data'=>array(
                '#type'=>'textfield',
                '#name' => 'classroom',
                '#size' => 12,
            ),
        ),
    );

    $form['table'] = array(
        '#theme' => 'demo_tableform_form',
        '#header' => $header,
        '#tree' => TRUE,
        '#rows' => $options,
        '#empty' => t('No content available.'),
    );

    $form['submit'] = array(
        '#type' => 'submit',
        '#submit' => array('classroomtable_submit'),
        '#value' => t('Save'),
    );

    return $form;
}

比较方便的是,利用rows array key的设置还能区分每一行的不同值,比如下面这段代码,表单提交后sex[3]就是用户在这行选择的值了,在多行表单中这种区分有时是非常有用的 :

 $key = 3;
 $options[$key] = array(
    'sex' =>array(
            'data' =>array(
                '#type'=>'select',
                '#name'=>'sex[{$key}]',
                '#options'=>array(
                    'F'=>'女',
                    'M'=>'男'
                ),
            ),
        ),
...

表格(table render)渲染部分:

/**
 * @return array
 */
function demo_tableform_theme()  
{
    return array(
        'demo_tableform_form' => array(
            'render element' => 'form',
        ),
    );
}

/**
 * @param $variable
 * @return string
 */
function theme_demo_tableform_form(&$variable)  
{
    $form = $variable['form'];
    $rows = $form['#rows'];
    $header = $form['#header'];
    $content = array(
        '#theme' => 'table',
        '#header' => $header,
        '#rows' => $rows,
    );
    return drupal_render($content);
}

最后把表单提交后的逻辑写一写就大功告成啦!表单提交内容用的是$form_state['input']内的值。

function classroomtable_submit($form, &$form_state){  
    $sex = $form_state['input']['sex']; //F or M
    $number = $form_state['input']['number']; //int
    $height = $form_state['input']['height']; //demecal
    $classroom = $form_state['input']['classroom'];  //text
    if($number <= 0 || !(is_numeric($number) && is_int($number+0))){
        form_set_error('number','请输入正确的人数');
    }elseif($height <= 0|| !(is_numeric($height))){
        form_set_error('height','请输入正确的身高');
    }else{
        $entity = entity_create('class_resourece',array('type'=>'class_resourece_basic'));
        $ew = entity_metadata_wrapper('class_resourece', $entity);
        $ew->created->set(time());
        $ew->field_gender->set($sex);
        $ew->field_numberof->set($number);
        $ew->field_heights->set($height);
        $ew->field_class->set($classroom);
        $ew->save();
        $form_state['redirect'] = '<front>';
    }
}