Как можно программно создать форму для изменения значений ССК поля ноды

11 ноября 2010 в 21:37
Аватар пользователя gorr gorr 0 12

Иногда может потребоваться изменять значения какого-то CCK поля ноды не обновляя всю ноду.
Выкладываю заготовку для решения такой задачи (по мотивам тестового задания restyler).
В нижеприведенном коде создаются пути типа 'test-form/%node', на страницах с этими адресами выводится форма для заполнения одного CCK поля (сейчас захардкоденного, но легко меняется на выбираемое из админки или даже несколько полей) и кнопка сабмита для отправки формы. После отправки поле соответственного нода будет обновлено, в том числе работает с полями множественного выбора. Например, если зайти на страницу 'test-form/4' и есть такой нод и у него есть поле 'field_test', то после сабмита формы на этой странице у нода 4 в поле field_test будут обновленные значения.
Валидацию не делал, надо доделывать, если будете использовать где-то.
<?php

/**
* Implementation of hook_menu().
*/
function test_module_menu() {
$items = array();
$items['test-form/%node'] = array(
'page callback' => 'drupal_get_form',
'page arguments' => array('test_form', 1),
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
return $items;
}

function test_form(&$form_state, $node) {
$form['#node'] = $node;
$field_name = 'field_test';
$field = content_fields($field_name, $node->type);
$form['#field_info'][$field_name] = $field;
module_load_include('inc', 'content', 'includes/content.node_form');
$form_element = content_field_form($form, $form_state, $field);
$form += (array)$form_element;
$form['submit'] = array(
'#weight' => 100,
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}

function test_form_submit($form, &$form_state) {
//$f_name = 'field_test';
$node = $form['#node'];
$type_name = $node->type;
$type = content_types($type_name);
foreach ($type['tables'] as $table) {
$schema = drupal_get_schema($table);
$record = array();
foreach ($schema['content fields'] as $field_name) {
if (isset($form_state['values'][$field_name])) {
$field = content_fields($field_name, $type_name);
// Multiple fields need specific handling, we'll deal with them later on.
if ($field['multiple']) {
continue;
}
$db_info = content_database_info($field);
foreach ($db_info['columns'] as $column => $attributes) {
$record[$attributes['column']] = $form_state['values'][$field_name][0][$column];
}
}
}
if (count($record) || empty($schema['content fields'])) {
$record['nid'] = $node->nid;
$record['vid'] = $node->vid;
if (db_result(db_query("SELECT COUNT(*) FROM {". $table ."} WHERE vid = %d", $node->vid))) {
content_write_record($table, $record, array('vid'));
}
else {
content_write_record($table, $record);
}
}
}

// Handle multiple fields.
foreach ($type['fields'] as $field) {
if ($field['multiple'] && isset($form_state['values'][$field['field_name']])) {
$db_info = content_database_info($field);
// Delete and insert, rather than update, in case a value was added.
db_query('DELETE FROM {'. $db_info['table'] .'} WHERE vid = %d', $node->vid);
foreach ($form_state['values'][$field['field_name']] as $delta => $item) {
if($delta === $field['field_name']. '_add_more') continue;
$record = array();
$not_empty = 0;
foreach ($db_info['columns'] as $column => $attributes) {
if($item[$column] && !$not_empty) $not_empty = 1;
$record[$attributes['column']] = $item[$column];
}
$record['nid'] = $node->nid;
$record['vid'] = $node->vid;
$record['delta'] = $delta;
//drupal_set_message(var_export($record, TRUE));
if($not_empty) content_write_record($db_info['table'], $record);
}
}
}
cache_clear_all('content:'. $node->nid .':'. $node->vid, content_cache_tablename());
}
?>

Комментарии

да чего же здесь красивого, это как вскрытие вместо массажа, вы все сделали за cck руками, когда надо поюзать node_save Smile

12 ноября 2010 в 12:53

[ru-api=node_save]node_save[/ru-api] обновляет все таблицы, связанные с типом материала ноды, а здесь речь идет об обновлении одной таблицы (для CCK поля)

12 ноября 2010 в 13:12

"restyler" wrote:
да чего же здесь красивого, это как вскрытие вместо массажа, вы все сделали за cck руками, когда надо поюзать node_save :)

node_save также вызывает все хуки в том числе, а иногда это не требуется, в моем случае это так, через node_save было бы попроще.

12 ноября 2010 в 13:38

задачи не совсем одинаковые, согласен.
просто ведь скажут потом, что нехороший restyler уж очень сложный таск для тестового задания придумал Smile

12 ноября 2010 в 15:43

"batbug" wrote:
наверное, хорошо будет использовать для инлайн-редактирования в аякс-окошке?

Тут возникнут проблемы с полями со множественными значениями, например текстовыми, которые добавляются и убираются с помощью ahah, так как в Drupal.settings на странице, на которой появится аяксом загруженный элемент, он не значится. Следовательно Drupal.attachBehaviors не отработает как надо.
Для решения этих проблем есть вспомогательный модуль ajax_load

15 ноября 2010 в 0:33