【问题标题】:Drupal deleting/updating wrong row in databaseDrupal 删除/更新数据库中的错误行
【发布时间】:2012-02-13 22:41:52
【问题描述】:

我有一组可以使用表单编辑和删除的项目。现在,所有项目都以字段集的形式显示在列表中。使用此方法创建字段集:

 $venues = db_query('SELECT vid, name, address, postcode, city FROM venues v WHERE v.uid = :uid', array(':uid' => $user->uid));
 if($venues->rowCount() != 0) {
   foreach($venues as $venue) {
     $page['venue_editing_form'][] = drupal_get_form('venue_editor_form', $venue->vid, $venue->name, $venue->address, $venue->postcode, $venue->city); 
   }
 }

然后用这个函数创建表单:

function venue_editor_form($form, &$form_state, $vid, $vname, $vadd, $vpostc, $vcity) {
$form['#prefix'] = '<div class="vedit">';
$form['#suffix'] = '</div>';
$form['edit_fieldset_'.$vname] = array(
  '#type' => 'fieldset',
  '#title' => t($vname),
  '#collapsible' => TRUE,
  '#collapsed' => TRUE,
  '#attributes' => array('class' => array('venue-edit')),
);
$form['edit_fieldset_'.$vname]['venue_name'] = array(
  '#type' => 'textfield',
  '#title' => t('Venue name:'),
  '#description' => t('Enter the venue name.'),
  '#default_value' => $vname,
  '#attributes' => array('onfocus' => 'this.value=""')
);
$form['edit_fieldset_'.$vname]['address'] = array(
  '#type' => 'textfield',
  '#title' => t('Address:'),
  '#description' => t('The address of this venue.'),
  '#default_value' => $vadd,
  '#attributes' => array('onfocus' => 'this.value=""')
);
$form['edit_fieldset_'.$vname]['postcode'] = array(
  '#type' => 'textfield',
  '#title' => t('Postcode'),
  '#description' => t('Enter the postcode for this event, so planB can position it on the map'),
  '#default_value' => $vpostc,
  '#attributes' => array('onfocus' => 'this.value=""', 'onblur' => 'getLatLong(this)')
);
$form['edit_fieldset_'.$vname]['city'] = array(
  '#type' => 'textfield',
  '#title' => t('City'),
  '#description' => t('The city this venue is in.'),
  '#default_value' => $vcity,
  '#attributes' => array('onfocus' => 'this.value=""')
);
$form['edit_fieldset_'.$vname]['edit_submit'] = array(
  '#type' => 'submit',
  '#value' => t('Submit changes'),
  '#validate' => array('venue_creation_form_validate')
);
$form['edit_fieldset_'.$vname]['delete_venue'] = array(
  '#type' => 'submit',
  '#value' => t('Delete venue'),
  '#submit' => array('venue_form_delete')
);
$form['edit_fieldset_'.$vname]['venueid'] = array(
  '#type' => 'value',
  '#value' => $vid
);
return $form;

}

还有一个提交处理程序:

function venue_form_delete($form, &$form_state) {
  $deleted = db_delete('venues')
    ->condition('vid', $form['#venueid'], '=')
    ->execute();
    drupal_set_message('Venue deleted successfully.');
}

现在,问题是无论我按下哪个场地的删除按钮,Drupal 总是删除列表中的第一个。出于某种原因,$form['#venueid'] 始终设置为提交处理程序列表中的第一个地点,但是如果我在生成表单时打印一条消息,则每个表单都有不同的 ID,应该是。

以前有人遇到过这个问题吗?

【问题讨论】:

  • 视频从哪里来?你是说nid吗?
  • vid 是场地ID,它来自数据库查询以获取所有场地的详细信息。然后,我使用 foreach 循环遍历所有结果和 drupal_get_form('venue_editor_form', $venue->vid ...)
  • 重读这个问题,是不是你有一个表单,有多个字段集和多个提交/删除按钮(即每个场地一个字段集)?
  • 有多个带有多个删除/更新按钮的字段集,但每个字段集只有一个表单。通过从数据库中获取场地并在调用 drupal_get_form 的 foreach 循环中创建表单。

标签: php mysql forms drupal drupal-7


【解决方案1】:

几周前,我的一位同事遇到了这个问题。您遇到此问题的原因是因为您尝试在具有不同数据的页面上多次加载相同的表单。看起来这应该可行,但它不是因为所有表单最终都具有相同的令牌/ ID。当您提交每个表单时,系统不知道您真正点击了哪个表单,因此无法采取适当的操作。

有两种方法可以解决这个问题:

1) 重做您的表单,以便全部使用 1 个表单而不是多个表单来处理

2) 使用hook_forms(...) 创建一个“基本表单”,然后为每个场地生成映射到“基本表单”的唯一表单。这将确保每个表单都获得一个唯一的 ID,而无需为每个表单编写表单。

我没有 drupal 7 示例,但这里有一个页面显示如何使用 hook_forms http://www.computerminds.co.uk/drupal-6-multiple-instances-same-form-one-page 解决您的 drupal 6 问题。您应该能够应用相同的技术

我没有测试过这段代码,但这是基本思想:

修改您的 get_form 以使用唯一 ID

foreach($venues as $venue) {
     $page['venue_editing_form'][] = drupal_get_form('venue_editor_form_'. $venue->vid, $venue->vid, $venue->name, $venue->address, $venue->postcode, $venue->city); 
   }

实现 hook_forms

function MODULENAME_forms($form_id) {
  $forms = array();
  if (preg_match('/venue_editor_form_/', $form_id) {
    $forms[$form_id] = array(
      'callback' => 'venue_editor_form',
    );
  }
  return $forms;
}

然后我认为您必须修改表单的提交参数以确保它们都被路由到同一个提交处理程序。虽然看起来您确实为每个按钮添加了不同的提交,但您可能不必在那里做任何事情

$form['#submit'] => array('venue_editing_form_submit');

您可能还必须对验证函数执行相同的操作。

应该这样做。

【讨论】:

  • 谢谢,这解决了问题。 Drupal 无法区分具有相同表单 ID 的提交,这就是它删除错误场所的原因!再次感谢。
【解决方案2】:

我猜问题是您尝试通过表单处理传递场地ID值而不使用显式值字段:

$form['#venueid'] = $vid;

这只是为“组成”表单属性(前导“#”)分配一个值,该属性通常不存在。尝试使用明确的value field type 代替:

$form['venueid'] = array(
    '#type' => 'value',
    '#value' => $node->vid
);

这样,vid 应该在您的提交函数中可用,就像任何其他表单值一样,即在$form_state['values']

function venue_form_delete($form, &$form_state) {
  $deleted = db_delete('venues')
    ->condition('vid', $form_state['values']['venueid'], '=')
    ->execute();
    drupal_set_message('Venue deleted successfully.');
}

请注意删除了“#”字符 - 前导“#”表示表单(和表单元素)属性,Drupal 将在表单处理期间尝试解释这些属性,而“#venueid”不是已定义的属性。

【讨论】:

  • 使用自定义 FAPI 属性是非常标准的做法(数十个贡献的模块都这样做,例如 Date 的 #date_format 键)。在数组中使用#'d 属性的唯一问题是可能与现有的命名属性发生冲突。这可以通过在属性名称前面加上负责实现它的模块的名称来避免,例如#mymodule_venueid。除此之外,此方法 100% 有效,不会导致所述问题。
  • @Clive:你说得对,许多 contrib 模块以一种或另一种方式做到这一点,但我不会称其为“标准做法”。使用这样的 FAPI 属性意味着依赖未记录的功能(可能随时更改),而不是使用官方的、记录的和推荐的替代方案(以“#value”类型元素的形式)。因此,我的建议旨在先尝试“正常”方式,然后再寻找未记录的“功能”问题。
  • @Clive:为了避免误解——对于“未记录”,我并不是指自定义 FAPI 属性本身的概念。如果想从自定义模块扩展 FAPI 功能,例如通过提供新的元素类型,他可以而且应该在需要时使用自定义属性(就像日期模块对#date_format 所做的那样)。但是这种属性的使用是针对表单生命周期内的表单元素处理/处理,而不是传递值来提交函数。
  • 我在很大程度上同意你的看法,除了说 Drupal core 实际上使用这种方法将任意数据传递给提交/验证函数。最好的例子是节点编辑表单,它在表单的整个生命周期中保持#node 属性,并不断地引用它。不过,我再次同意你所说的。也许最好的折衷方案是让 Drupal 实际生成有关此类事情的文档。那么至少这个问题会有一个明确的“Drupal”答案
  • 感谢您的回答,但正如有人指出的那样,这没有任何区别。我已经更改了我的代码以反映更“标准化”的技术。感谢你们俩花时间研究它。
猜你喜欢
  • 1970-01-01
  • 2014-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-29
相关资源
最近更新 更多