function conflict_node_validate in Conflict 7
Implements hook_node_validate().
File
- ./
conflict.module, line 52 - Fieldwise conflict prevention and resolution. @author Brandon Bergren
Code
function conflict_node_validate($node, &$form, &$form_state) {
if (isset($node->nid) && node_last_changed($node->nid) > $node->changed && variable_get('conflict_enable_' . $node->type, FALSE)) {
// We only support nodes for now.
$entity_type = 'node';
// Bypass the core conflict detector.
$errors =& drupal_static('form_set_error', array());
if (!empty($errors['changed'])) {
unset($errors['changed']);
// Remove the message as well.
foreach ($_SESSION['messages']['error'] as $k => $v) {
if ($v == t('The content on this page has either been modified by another user, or you have already submitted modifications using this form. As a result, your changes cannot be saved.')) {
unset($_SESSION['messages']['error'][$k]);
$_SESSION['messages']['error'] = array_values($_SESSION['messages']['error']);
}
if (empty($_SESSION['messages']['error'])) {
unset($_SESSION['messages']['error']);
}
}
}
$nodes = array();
// Base node: The common ancestor that was cached when beginning the node
// edit.
$nodes['base'] = clone $form_state['node'];
// Theirs: The current state of the node, with the changes that happened in
// parallel.
$nodes['theirs'] = clone node_load($node->nid, NULL, TRUE);
// This workaround is done because the $node object in this hook does not
// have processed fields and would be inconsistent during comparison.
_field_invoke_multiple('load', 'node', array(
$nodes['theirs']->nid => $nodes['theirs'],
));
// Mine: The node that was about to be saved.
$tmp_form_state = $form_state;
$nodes['mine'] = node_form_submit_build_node($form, $tmp_form_state);
_field_invoke_multiple('load', 'node', array(
$nodes['mine']->nid => $nodes['mine'],
));
// Store fields names to highlight them after form rebuild.
$error_fields = array();
// Dig through the fields looking for conflicts.
$updated = FALSE;
$remote_changes = _conflict_get_node_changes($nodes['base'], $nodes['theirs']);
if (!empty($remote_changes)) {
$local_changes = _conflict_get_node_changes($nodes['mine'], $nodes['base']);
$real_changes = _conflict_get_node_changes($nodes['mine'], $nodes['theirs']);
$conflicted_fields = array_intersect($local_changes, $remote_changes, $real_changes);
$changed_fields = array_diff($remote_changes, array_intersect($local_changes, $remote_changes));
foreach ($conflicted_fields as $field_name => $field_title) {
// If the field can have unlimited values, check if the added values
// from mine & theirs can be merged.
$field = field_info_field($field_name);
if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED && $field['type'] != 'taxonomy_term_reference') {
// todo handling taxonomy_term_reference fields would be nice.
$field_language = field_language('node', $form_state['node'], $field_name);
$columns = array_keys($field['columns']);
$same = TRUE;
foreach ($nodes['base']->{$field_name}[$field_language] as $delta => $value) {
foreach ($columns as $column) {
if (!isset($nodes['mine']->{$field_name}[$field_language][$delta][$column]) || $value[$column] != $nodes['mine']->{$field_name}[$field_language][$delta][$column] || !isset($nodes['theirs']->{$field_name}[$field_language][$delta][$column]) || $value[$column] != $nodes['theirs']->{$field_name}[$field_language][$delta][$column]) {
$same = FALSE;
break;
}
}
}
if ($same) {
// The values in base match both mine & theirs. Merge added values.
unset($form_state['input'][$field_name]);
$nodes['theirs']->{$field_name}[$field_language] = array_merge($nodes['theirs']->{$field_name}[$field_language], array_slice($nodes['mine']->{$field_name}[$field_language], $delta + 1));
drupal_set_message(t('The @label field was also changed by another user. Your additions have been merged together. Please verify the updated values and save.', [
'@label' => $field_title,
]), 'warning');
$updated = TRUE;
continue;
}
}
drupal_set_message(t('The @label field was changed by another user while you were editing it. Save again to overwrite it.', array(
'@label' => $field_title,
)), 'error');
$updated = TRUE;
$error_fields[] = $field_name;
}
foreach ($changed_fields as $field_name => $field_title) {
// Forget the user-submitted value.
unset($form_state['input'][$field_name]);
drupal_set_message(t('The @label field was changed by another user. Please verify the updated value.', array(
'@label' => $field_title,
)), 'warning');
$updated = TRUE;
$error_fields[] = $field_name;
}
}
if ($updated) {
// Reload the node to pick up the updated data.
$node = clone $nodes['theirs'];
node_object_prepare($node);
$form_state['node'] = $node;
$form_state['rebuild'] = TRUE;
$form_state['temporary']['conflict_fields'] = $error_fields;
}
}
}