When we update user and change multi-value without change of ammount of values - all ok.
And when we add more values - all ok.
But when we decrease amount of values for multi-field - we have bug.

Comments

uzlov created an issue. See original summary.

uzlov’s picture

Status: Active » Needs review
StatusFileSize
new1.3 KB

Status: Needs review » Needs work

The last submitted patch, 2: services-update_multi_value_fields_of_user-2598048-1.patch, failed testing.

uzlov’s picture

uzlov’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 4: services-update_multi_value_fields_of_user-2598048-2.patch, failed testing.

uzlov’s picture

patch not actual, because for support of multifields need to rewrite (or use custom) drupal_form_submit

something like it (not sure that we need it in services - more simply to use alter of resources)


/**
 * Implements hook_services_resources_alter().
 */
function mymodule_services_auth_services_resources_alter(&$resources, &$endpoint) {
  $resources['user']['operations']['update']['callback'] = '_mymodule_user_resource_update';
}

/**
 * Update an existing user.
 *
 * This function uses drupal_form_submit() and as such expects all input to match
 * the submitting form in question.
 *
 * @param $uid
 *   Unique identifier for this user
 * @param $account
 *   Fields to modify for this user.
 *
 * @return
 *   The modified user object.
 */
function _mymodule_user_resource_update($uid, $account) {
  // Adds backwards compatability with regression fixed in #1083242
  $account = _services_arg_value($account, 'data');

  $account['uid'] = $uid;

  $account_loaded = user_load($uid);

  // Load the required includes for saving profile information
  // with drupal_form_submit().
  module_load_include('inc', 'user', 'user.pages');

  // If a profile category was passed in, use it. Otherwise default
  // to 'account' (for saving core user data.)
  $category = 'account';
  if (isset($account['category'])) {
    $category = $account['category'];
    unset($account['category']);
  }

  // Drop any passed in values into the $account var. Anything
  // unused by the form just gets ignored. We handle roles and
  // password separately.
  foreach ($account as $key => $value) {
    if ($key != 'pass' && $key != 'roles') {
      // Generate empty values for multivalue fields.
      $field_info = field_info_field($key);
      if (!empty($field_info) && $field_info['cardinality'] != 1) {
        foreach ($value as $lang => $values) {
          $count = count($account[$key][$lang]);
          $count_loaded = isset($account_loaded->{$key}[$lang]) ? count($account_loaded->{$key}[$lang]) : 0;
          if ($count_loaded > $count) {
            $empty_value = array();
            foreach ($field_info['columns'] as $column_name => $column) {
              $empty_value[$column_name] = $column['default'];
            }
            for ($i = 0; $i < $count_loaded - $count; $i++) {
              $value[$lang][] = $empty_value;
            }
          }
        }
      }
      $form_state['values'][$key] = $value;
    }
  }

  // Prepare values of roles. Check user's permission before allowing changes to roles.
  if (!isset($account['roles']) || !user_access('administer users')) {
    $account['roles'] = $account_loaded->roles;
  }
  foreach ($account['roles'] as $key => $value) {
    if (!empty($value)) {
      $form_state['values']['roles'][$key] = $key;
    }
  }
  unset($form_state['values']['roles'][2]);

  // Prepare values for password.
  if (isset($account['pass'])) {
    $form_state['values']['pass']['pass1'] = $account['pass'];
    $form_state['values']['pass']['pass2'] = $account['pass'];
  }

  // If user is changing name, make sure they have permission.
  if (isset($account['name']) && $account['name'] != $account_loaded->name && !(user_access('change own username') || user_access('administer users'))) {
    return services_error(t('You are not allowed to change your username.'), 406);
  }

  $form_state['values']['op'] = variable_get('services_user_save_button_resource_update', t('Save'));
  $form_state['values']['#user_category'] = $category;
  $form_state['values']['#account'] = $account_loaded;
  $form_state['programmed_bypass_access_check'] = FALSE;
  $ret = drupal_form_multi_values_submit('user_profile_form', $form_state, $account_loaded, $category);

  // Error if needed.
  if ($errors = form_get_errors()) {
    return services_error(implode(" ", $errors), 406, array('form_errors' => $errors));
  }
  else {
    $account = (object) $account;
    services_remove_user_data($account);
    $account = (array) $account;
    _user_resource_update_services_user($uid, time());
    return $account;
  }
}

/**
 * Retrieves, populates, and processes a form.
 */
function drupal_form_multi_values_submit($form_id, &$form_state) {
  if (!isset($form_state['build_info']['args'])) {
    $args = func_get_args();
    array_shift($args);
    array_shift($args);
    $form_state['build_info']['args'] = $args;
  }
  // Merge in default values.
  $form_state += form_state_defaults();

  // Populate $form_state['input'] with the submitted values before retrieving
  // the form, to be consistent with what drupal_build_form() does for
  // non-programmatic submissions (form builder functions may expect it to be
  // there).
  $form_state['input'] = $form_state['values'];

  $form_state['programmed'] = TRUE;
  $form = drupal_retrieve_form($form_id, $form_state);
  // Programmed forms are always submitted.
  $form_state['submitted'] = TRUE;

  // Loop through fields to discover multiple fields
  foreach(element_children($form_state['values']) as $fieldname) {
    // Look for fields with mmore than one value
    if( count($form_state['values'][$fieldname]['und']) > 1 ) {
      $element = drupal_array_get_nested_value($form, array($fieldname,'und'));
      $field_name = $element['#field_name'];
      $langcode = $element['#language'];
      $parents = $element['#field_parents'];

      // Increment the items count.
      $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
      $field_state['items_count'] = count($form_state['values'][$fieldname]['und']) - 1;
      field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);

      $form = drupal_rebuild_form($form_id, $form_state, $form);
    }
  }

  // Reset form validation.
  $form_state['must_validate'] = TRUE;
  form_clear_error();

  drupal_prepare_form($form_id, $form, $form_state);
  drupal_process_form($form_id, $form, $form_state);
}
kylebrowning’s picture

Status: Needs work » Closed (duplicate)
uzlov’s picture

not fully
it issue with update user entity

#2224803: Possible patch for multi-value fields - for update nodes

kylebrowning’s picture

@uzlov Yeah, id like to solve it for all resources, not just one by one.