drupal_get_form, 让drupal认得它是个form
form需要用drupal_get_form来加工,system才会把它认为是form,其实最终form的array也是drupal_render进行处理,drupal_get_form仅仅是给array添加让system认定为form的基本数据。
drupal_render接收的参数是一个array,它认为array嵌套的元素都是一个array,除非用#这个特殊键值声明。例如array('#markup' => '<span>....</span>');
form, form_state - form用于前后交互的变量
form的callback function都会有form和form_state两个参数,form用于生成form的结构,最终输出到页面上,form_state用于保存form的状态,并可以在callback之间转递数据。
在$form中,所有不带#开头的键名会被视为表单元素或分组元素;带#开头的键名会被视为表单元素的属性。
$form_state除了交互数据外,还有一些键名有特殊作用:
$form_state['input']
$form_state['values'] : 从form post过来的所有值
$form_state['redirect'] : 让form完成submit后自动跳转到指定页面
$form_state['rebuild']
给form制作一个template
从官方的drupal api document中可得到form有#theme这个参数,它可以指定form使用一个模板来用于form的基本布局,#theme的值必须是通过hook_theme声明的key。一般情况下,即使不去声明#theme,#theme也会有一个与本form同名的默认值,所以只需要用hook_theme声明一个与form name一样的key就可以。mymodule.module:
function mymodule_form(){
// ...
return $form;
}
function mymodule_theme() {
return array(
// theme name与form ID一样。这是由于每个form[#theme]都有一个等于form ID的默认值。
'mymodule_form' => array(
'render element' => 'form',
'template' => 'mymodule-form', // 对应文件名mymodule-form.tpl.php
),
);
}
mymodule-form.tpl.php:
<?php $form = $variables['form'];?>
<?php echo drupal_render($form['name']); // 'name' form element ?>
<?php echo drupal_render_children($form); // print other all form element ?>
修改其它form同理,先用devel确认form的#theme值,然后使用hook_theme创建对应的key。如果form已经有template,可以使用hook_form_alter把#theme修改为另外的名。
修改一个已存在的form
可以使用hook_form_alter修改form的内容,前提是得到form ID(drupal中所有form都会有一个form ID,一般与创建form的函数名相同)
Link
以下方法可以输出所有form的form ID,得到form ID才可以对form进行单独操作,建议加到theme下的template.php中,命名为mytheme_form_alter (mytheme要改为当前theme的名字)
function mytheme_form_alter(&$form, &$form_state, $form_id) {
$print = '<pre>' . print_r($form, TRUE) . '</pre>';
if (module_exists('devel')) {
dsm($form_id); // print form ID to messages
}
else {
drupal_set_message($form_id); // print form ID to messages
}
if (module_exists('devel')) {
dsm($form); // pretty print array using Krumo to messages
}
else {
drupal_set_message($print); // print array to messages
}
}
提取node form
function example_form($form, &$form_state, $node = NULL) {
if (!$node) {
$node = new stdClass();
$node->type = 'page';
$node->title = '';
$node->language = LANGUAGE_NONE;
}
$form_state['#node'] = $node;
field_attach_form('node', $node, $form, $form_state);
$form['actions'] = array(
'#type' => 'actions'
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save')
);
return $form;
}
function example_form_submit($form, &$form_state) {
global $user;
$node = $form_state['#node'];
if(!isset($node->uid)){
$node->uid = $user->uid;
}
field_attach_submit('node', $node, $form, $form_state);
node_save($node);
}
free element, 使用传统的方法呈现element
function mymodule_form(){
// 必须存在,否则submit无法得到chk的值
$form['chk']= array(
'#type' => 'hidden'
);
$form['html'] = array(
'#markup' => '<input type="checkbox" name="chk[]" value="1"/>|||<input type="checkbox" name="chk[]" value="2"/>'
);
$form['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
return $form;
}
隐藏表单元素
$form['any']['#access'] = false; // 不可见
$form['any']['#value'] = $default_value; // 强制设置value,不接受post数据
element group的form error,当form的元素层次很多时,error的处理会比较特别
一般用法:form_set_error('field_image', $message);
如果form用了多层次的element,例如$form['group'][0]['field_image'],这时需要写成:form_set_error('group][0][field_image', $message);
form element 分组
$form['parent'] = array(
'#type' => 'fieldset',
'#tree' => true, // 承认有子元素,否则只能取值$form_state['value']['child']
'child' => array(
'#type' => 'textfield'
)
);
// 以上元素取值如下
$form_state['values']['parent']['child'];
redirect,form提交后将去到什么页面?
drupal中很常见用drupal_goto进行跳转,无论在什么地方,都会强调被跳转。但不应该用在form的validate和submit的callback中,这是因为validate和submit可以接受多个callback,如果中途被GOTO了,后台的callback就无法执行。正常的方法是使用redirect参数
$form_state['redirect'] = 'node/1';
所有form的架构、验证、提交函数,必须在.module或者显式引入外部文件
如果form function不在module引入,有可能在提交后或者AJAX后找不到对应的function
给一个form增加更多的动作
/**
* Implementation of hook_form_alter().
*/
function mymodule_form_alter(&$form, &$form_state, $form_id){
if($form_id == 'article_node_form')) {
$form['actions']['submit']['#submit'][] = 'mymodule_article_node_form_submit';
}
}
function mymodule_article_node_form_submit($form, &form_state) {
// 表单提交后跳转到首页
$form_state['redirect'] = 'node';
}
register a new user
// register a new user
$form_state = array();
$form_state['values']['name'] = 'robo-user';
$form_state['values']['mail'] = 'robouser@example.com';
$form_state['values']['pass'] = 'password';
$form_state['values']['op'] = t('Create new account');
drupal_execute('user_register', $form_state);
3 个回答
选择
可以用 theme 优化
/**
* Implements hook_form_alter().
*/
function
hook_form_alter(&
$form
, &
$form_state
,
$form_id
) {
if
(
$form_id
==
'user_login'
) {
$form
[
'#theme'
] =
array
(
'overwrite_user_login'
);
}
}
/**
* Implements hook_theme().
*/
function
hook_theme(
$existing
,
$type
,
$theme
,
$path
){
return
array
(
'overwrite_user_login'
=>
array
(
'render element'
=>
'form'
,
'template'
=>
'form--user_login'
,
'path'
=>
$path
.
'/templates'
,
),
);
}
然后增加 form--user_login.tpl.php文件
<?php
print
drupal_render_children(
$form
)
?>
信念LV 10
4 年前回答该问题
288
谢谢,这个方法是可行的!不过有没有直接修改原生的表单的方法呢?
还有用theme的方法如何打印#token和#build_id?
没有#token和#build_id对安全性有影响没有?
春田镇三眼鱼LV 9
4 年前回答该问题
206
以user_register表单为例:
定义一个函数
your_theme_name_ 或者 phptemplate_ 加 name_of_form($form).
如
<?php
function
phptemplate_user_register(
$form
) {
$variables
=
array
(
'user'
=>
$user
,
'form'
=>
$form
);
return
_phptemplate_callback(
'user_register'
,
$variables
);
}
?>
然后创建同名tpl.php , 如本例是:user_register.tpl.php
<?php
drupal_set_message(
'< pre >'
. var_export(
$variables
,TRUE) .
'< /pre >'
);
?>
<div id=
"regform1"
>
<fieldset
class
=
"group-account-basics collapsible"
><legend>Account Basics</legend>
<?php
print
drupal_render(
$form
[
'name'
]); ?>
<?php
print
drupal_render(
$form
[
'mail'
]); ?>
<?php
print
drupal_render(
$form
[
'pass'
]); ?>
<?php
print
drupal_render(
$form
[
'field_user_picture'
]); ?>
<?php
print
drupal_render(
$form
[
'field_city'
]); ?>
</fieldset>
</div>
<div id=
"regform2"
>
<fieldset
class
=
"group-story collapsible"
><legend>My Story</legend>
<?php
print
drupal_render(
$form
[
'field_storypic'
]); ?>
<?php
print
drupal_render(
$form
[
'field_user_story_field'
]); ?>
</fieldset>
</div>
<?php
print
drupal_render(
$form
[
'captcha'
]); ?>
<?php
print
drupal_render(
$form
[
'submit'
]); ?>
<?php
unset(
$form
[
'field_mostimportantlesson'
]);
print
drupal_render(
$form
);
?>