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

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

Иногда может потребоваться изменять значения какого-то 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());
}
?>

Комментарии

Аватар пользователя gorr gorr 11 ноября 2010 в 22:35

Ты прав, Сергей, она лишней оказалась, просто забыл убрать. Закомментировал ее.

Аватар пользователя goodboy goodboy 11 ноября 2010 в 22:46

Да, теперь все красиво. Спасибо за код, Игорь. Думаю, многим пригодится.

Аватар пользователя restyler restyler 12 ноября 2010 в 12:53

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

Аватар пользователя goodboy goodboy 12 ноября 2010 в 13:12

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

Аватар пользователя gorr gorr 12 ноября 2010 в 13:38

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

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

Аватар пользователя restyler restyler 12 ноября 2010 в 15:43

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

Аватар пользователя Виктор Степаньков ака RxB Виктор Степаньк... 14 ноября 2010 в 19:14

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

+41
не знаю верного решения, но наверно это так

Аватар пользователя batbug batbug 14 ноября 2010 в 21:42

подписался.

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

Аватар пользователя gorr gorr 15 ноября 2010 в 0:33

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

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