Иногда может потребоваться изменять значения какого-то 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());
}
?>
Комментарии
Не могу понять, зачем эта строка:
$f_name = 'field_test';
Ты прав, Сергей, она лишней оказалась, просто забыл убрать. Закомментировал ее.
Да, теперь все красиво. Спасибо за код, Игорь. Думаю, многим пригодится.
да чего же здесь красивого, это как вскрытие вместо массажа, вы все сделали за cck руками, когда надо поюзать node_save
[ru-api=node_save]node_save[/ru-api] обновляет все таблицы, связанные с типом материала ноды, а здесь речь идет об обновлении одной таблицы (для CCK поля)
node_save также вызывает все хуки в том числе, а иногда это не требуется, в моем случае это так, через node_save было бы попроще.
задачи не совсем одинаковые, согласен.
просто ведь скажут потом, что нехороший restyler уж очень сложный таск для тестового задания придумал
+41
не знаю верного решения, но наверно это так
в закладки!
подписался.
наверное, хорошо будет использовать для инлайн-редактирования в аякс-окошке?
в закладки
Тут возникнут проблемы с полями со множественными значениями, например текстовыми, которые добавляются и убираются с помощью ahah, так как в Drupal.settings на странице, на которой появится аяксом загруженный элемент, он не значится. Следовательно Drupal.attachBehaviors не отработает как надо.
Для решения этих проблем есть вспомогательный модуль ajax_load