3

I'm developing a module where I have to set a user profile date_field. I tried several methods to implement this but not one worked for me.

This is the code I am using.

private function updateUser($user_import,$uid = null) {
  if (!$uid) {
    return false;
  }

  $roles = $this->matchRoles($user_import->roles);
  $birthday = $this->birthdayDate($user_import->profile_geburtsdatum);
  $language = \Drupal::languageManager()->getCurrentLanguage()->getId();

  $user = \Drupal\user\Entity\User::load($uid);
  // $user->setPassword($this->randomPassword());
  $user->setEmail($user_import->mail);
  $user->setUsername($user_import->name);
  $user->enforceIsNew(false);

  // Optional settings
  $user->set("init", $user_import->init);
  $user->set("langcode", $language);
  $user->set("preferred_langcode", $language);
  $user->set("preferred_admin_langcode", $language);

  foreach ($roles as $role) {
    $user->addRole($role);
  }

  $user->set("field_profile_geburtsdatum", array('#default_value' => $birthday));
  $user->activate();
  $user->save();

  drupal_set_message("UPDATE: User " . $user_import->name . ' ( '. $user_import->mail . ')');
}

private function birthdayDate($import_date) {
  $date = null;
  if (!empty($import_date)) {
    $date = strtotime($import_date->day.'.'.$import_date->month.'.'.$import_date->year);
    $date = date('Y-m-d 00:00:00',$date);
    $date = new \Drupal\Core\Datetime\DrupalDateTime($date, 'Europe/Berlin');

    /* $date = array(
         'year' => date('Y',$date),
         'month' => date('m',$date),
         'day' => date('d',$date),
       );
     */
  }

  return $date;
}
0

3 Answers 3

9

Assuming field_profile_geburtsdatum is configured as a singular date-only datetime field, the following are all equivalent in the Field API (in order of my preferred usage):

$user->field_profile_geburtsdatum = '1999-12-31';
$user->field_profile_geburtsdatum->value = '1999-12-31';
$user->field_profile_geburtsdatum->set(0, '1999-12-31');
$user->set('field_profile_geburtsdatum', ['1999-12-31']);

The value you set should be a string in the DATETIME_DATE_STORAGE_FORMAT, which is 'Y-m-d', and not a DrupalDateTime object. That is used internally by the field type.

0
3

Since Drupal 8.5.x this works a little differently.

Firstly it's good practice to set the timezone explicitly so you know what is going on:

Set the timezone:

$timezone = new \DateTimeZone('UTC');
// Or
$timezone = new \DateTimeZone(date_default_timezone_get());
// Or 
$timezone = new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE);

Then create the date object using the PHP DateTime class:

$date_time = new \DateTime('now', $timezone);
$drupal_date_time = DrupalDateTime::createFromDateTime($date_time);

Or the DrupalDateTime class:

$drupal_date_time = new DrupalDateTime('yesterday', $timezone);

I like to use DateTime (or DateTimeImmutable) and then pass into the DrupalDateTime wrapper. That way native methods are highlighted in the IDE and also date comparisons (e.g. $now > $somedatetime work reliably.

Prior to saving the date/time you must set the timezone to DateTimeItemInterface::STORAGE_TIMEZONE:

$drupal_date_time->setTimezone(new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE))

You can then format the date for storage using the the DateTimeItemInterface::DATETIME_STORAGE_FORMAT constant:

$drupal_date_time->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT)

Here is an example based on above use case:

$timezone = new \DateTimeZone('Europe/Berlin');

// geburtsdatum = 'date of birth' :-)
$birthday_import_object = $user_import->profile_geburtsdatum;

$day = $birthday_import_object->day;
$month = $birthday_import_object->month;
$year = $birthday_import_object->year;

$birthday = new \DateTime($day.' '.$month.' '.$year, $timezone);

// Optionally convert to DrupalDateTime if you need the custom methods, etc
$birthday = DrupalDateTime::createFromDateTime($birthday);

$user->set(
  'field_profile_geburtsdatum',
  $birthday
    ->setTimezone(new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE))
    ->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT)
);
2
0
$user->set('field_profile_geburtsdatum', [['value' => $birthday]]);

There are two issues with the call to set in the question.

  1. A field requires to set an indexed array of values. This will call FieldItemBase::setValue().
  2. Each array within the values array should be keyed by the properties of that field. In this case value, not #default_value.

It is understandably confusing because as of this time there is no clear documentation around setting field items in either the Entity API section of Develop for Drupal or on api.drupal.org.

1
  • It's not clear where this would best be added (in the typed data section of entity api? wait until the docs pages are all migrated?), but it would probably be best to make the parameters in FieldableEntityInterface::set much more verbose instead of the dubious mixed type.
    – mradcliffe
    Commented Sep 8, 2016 at 17:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.