diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php index e1d6f0a..7bfe02c 100644 --- a/core/lib/Drupal/Core/Render/Renderer.php +++ b/core/lib/Drupal/Core/Render/Renderer.php @@ -331,10 +331,11 @@ protected function doRender(&$elements, $is_root_call = FALSE) { '#weight', '#printed' ]; - // Note to reviewers: I cannot explain this. The #attached is present key - // is present as an empty array and breaks the rendering with the bellow - // exception: \DomainException. I added this code to pass - if (is_array($elements['#attached']) && empty($elements['#attached'])) { + // Note to reviewers: I cannot explain this. The #attached key is present + // as an empty array and breaks the rendering with the bellow exception: + // \DomainException. I added this code to make the rendering passing. Is + // this a bug? + if (array_key_exists('#attached', $elements) && empty($elements['#attached'])) { $supported_keys[] = '#attached'; } $unsupported_keys = array_diff(array_keys($elements), $supported_keys); diff --git a/core/modules/user/config/schema/user.entity_schema.yml b/core/modules/user/config/schema/user.entity_schema.yml new file mode 100644 index 0000000..d0ef74c --- /dev/null +++ b/core/modules/user/config/schema/user.entity_schema.yml @@ -0,0 +1,29 @@ +# Schema for formatter settings defined bu user module. + +field.formatter.settings.user_timestamp: + type: mapping + label: 'Timestamp display format settings' + mapping: + date_format: + type: string + label: 'Date format' + custom_date_format: + type: string + label: 'Custom date format' + timezone: + type: string + label: 'Time zone' + +field.formatter.settings.user_timestamp_ago: + type: mapping + label: 'Timestamp ago display format settings' + mapping: + future_format: + type: string + label: 'Future format' + past_format: + type: string + label: 'Past format' + granularity: + type: integer + label: 'Granularity' diff --git a/core/modules/user/src/Plugin/Field/FieldFormatter/UserTimestampAgoFormatter.php b/core/modules/user/src/Plugin/Field/FieldFormatter/UserTimestampAgoFormatter.php index da3b9c0..7519971 100644 --- a/core/modules/user/src/Plugin/Field/FieldFormatter/UserTimestampAgoFormatter.php +++ b/core/modules/user/src/Plugin/Field/FieldFormatter/UserTimestampAgoFormatter.php @@ -28,10 +28,16 @@ class UserTimestampAgoFormatter extends TimestampAgoFormatter { */ public function viewElements(FieldItemListInterface $items, $langcode) { $arguments = []; - // Add the timestamp. - $arguments[] = !empty($items[0]->value) ? (int) $items[0]->value : NULL; - // Add the formatter settings. - $arguments[] = serialize($this->getSettings()); + // Add the field name. + $arguments[] = $this->fieldDefinition->getName(); + // Add the host entity id. + $arguments[] = $items->getEntity()->id(); + // Add the 'past_format' setting. + $arguments[] = $this->getSetting('past_format'); + // Add the 'future_format' setting. + $arguments[] = $this->getSetting('future_format'); + // Add the 'granularity' setting. + $arguments[] = $this->getSetting('granularity'); return [[ '#lazy_builder' => ['user.lazy_builders:renderTimestampAgo', $arguments], diff --git a/core/modules/user/src/Plugin/Field/FieldFormatter/UserTimestampFormatter.php b/core/modules/user/src/Plugin/Field/FieldFormatter/UserTimestampFormatter.php index 4713a22..e3be894 100644 --- a/core/modules/user/src/Plugin/Field/FieldFormatter/UserTimestampFormatter.php +++ b/core/modules/user/src/Plugin/Field/FieldFormatter/UserTimestampFormatter.php @@ -28,10 +28,16 @@ class UserTimestampFormatter extends TimestampFormatter { */ public function viewElements(FieldItemListInterface $items, $langcode) { $arguments = []; - // Add the timestamp. - $arguments[] = !empty($items[0]->value) ? (int) $items[0]->value : NULL; - // Add the formatter settings. - $arguments[] = serialize($this->getSettings()); + // Add the field name. + $arguments[] = $this->fieldDefinition->getName(); + // Add the host entity id. + $arguments[] = $items->getEntity()->id(); + // Add the 'date_format' setting. + $arguments[] = $date_format = $this->getSetting('date_format'); + // Add the 'custom_date_format' setting. + $arguments[] = $date_format === 'custom' ? $this->getSetting('custom_date_format') : ''; + // Add the 'timezone' setting. + $arguments[] = $this->getSetting('timezone') ?: NULL; return [[ '#lazy_builder' => ['user.lazy_builders:renderTimestamp', $arguments], diff --git a/core/modules/user/src/Tests/Update/UserUpdateTest.php b/core/modules/user/src/Tests/Update/UserUpdateTest.php new file mode 100644 index 0000000..34b5f94 --- /dev/null +++ b/core/modules/user/src/Tests/Update/UserUpdateTest.php @@ -0,0 +1,48 @@ +databaseDumpFiles = [ + __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz', + ]; + } + + /** + * Tests the post update user_post_update_timestamp_formatter() + * + * @see user_post_update_timestamp_formatter() + */ + public function testPostUpdateTimestampFormatter() { + // Check that for initial formatter in 'user_admin_people' view. + $view = $this->config('views.view.user_admin_people'); + $this->assertEqual('timestamp_ago', $view->get('display.default.display_options.fields.access.type')); + + // Run updates. + $this->runUpdates(); + + // Check that the 'user_admin_people' view was updated. + $view = $this->config('views.view.user_admin_people'); + $this->assertEqual('user_timestamp_ago', $view->get('display.default.display_options.fields.access.type')); + } + +} diff --git a/core/modules/user/src/UserLazyBuilders.php b/core/modules/user/src/UserLazyBuilders.php index 6d8c2af..56740c1 100644 --- a/core/modules/user/src/UserLazyBuilders.php +++ b/core/modules/user/src/UserLazyBuilders.php @@ -10,6 +10,7 @@ use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\user\Entity\User; use Symfony\Component\HttpFoundation\RequestStack; /** @@ -49,54 +50,58 @@ public function __construct(DateFormatterInterface $date_formatter, RequestStack /** * Provides a '#lazy_builder' callback for the 'user_timestamp' formatter. * - * @param int $timestamp - * Timestamp to format. - * @param string $settings - * The serialized formatter settings + * @param string $field_name + * The filed name. + * @param int $account_id + * The user id. + * @param string $date_format + * The date format. + * @param string $custom_date_format + * The custom date format. + * @param string $timezone + * The timezone. * * @return array * A renderable array with the formatted timestamp. */ - public function renderTimestamp($timestamp, $settings) { - $settings = unserialize($settings); - $date_format = $settings['date_format']; - $custom_date_format = ''; - $timezone = !empty($settings['timezone']) ? $settings['timezone'] : NULL; + public function renderTimestamp($field_name, $account_id, $date_format, $custom_date_format, $timezone) { + $timestamp = User::load($account_id)->get($field_name)->value; $langcode = NULL; - // If an RFC2822 date format is requested, then the month and day have to be // in English. // @see http://www.faqs.org/rfcs/rfc2822.html - if ($date_format === 'custom' && ($custom_date_format = $settings['custom_date_format'] === 'r')) { + if ($date_format === 'custom' && $custom_date_format === 'r') { $langcode = 'en'; } - return [ - '#markup' => $this->dateFormatter->format($timestamp, $date_format, $custom_date_format, $timezone, $langcode) - ]; + return ['#markup' => $this->dateFormatter->format($timestamp, $date_format, $custom_date_format, $timezone, $langcode)]; } /** * Provides a '#lazy_builder' callback for the 'user_timestamp_ago' formatter. * - * @param int $timestamp - * Timestamp to format. - * @param string $settings - * The serialized formatter settings + * @param string $field_name + * The filed name. + * @param int $account_id + * The user id. + * @param string $past_format + * The format used for past dates. + * @param string $future_format + * The format used for future dates. + * @param string $granularity + * The time granularity. * * @return array * A renderable array with the formatted timestamp. */ - public function renderTimestampAgo($timestamp, $settings) { - if (!$timestamp) { + public function renderTimestampAgo($field_name, $account_id, $past_format, $future_format, $granularity) { + if (!$timestamp = User::load($account_id)->get($field_name)->value) { // Exit early if the timestamp is empty. return ['#markup' => $this->t('never')]; } - - $settings = unserialize($settings); - $format = $this->request->server->get('REQUEST_TIME') > $timestamp ? 'past_format' : 'future_format'; - $options = ['granularity' => $settings['granularity']]; - return ['#markup' => new FormattableMarkup($settings[$format], ['@interval' => $this->dateFormatter->formatTimeDiffSince($timestamp, $options)])]; + $format = $this->request->server->get('REQUEST_TIME') > $timestamp ? $past_format : $future_format; + $options = ['granularity' => $granularity]; + return ['#markup' => new FormattableMarkup($format, ['@interval' => $this->dateFormatter->formatTimeDiffSince($timestamp, $options)])]; } } diff --git a/core/modules/user/user.post_update.php b/core/modules/user/user.post_update.php new file mode 100644 index 0000000..06aee66 --- /dev/null +++ b/core/modules/user/user.post_update.php @@ -0,0 +1,58 @@ +clearCachedDefinitions(); + + // Update view displays. Drupal doesn't expose, by default, these fields in + // 'user' view displays but we don't know what other contrib are doing. + foreach (EntityViewDisplay::loadMultiple() as $display) { + /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $display */ + if ($display->getTargetEntityTypeId() === 'user') { + $changed = FALSE; + foreach ($display->getComponents() as $component_id => $component) { + if (isset($component['type']) && in_array($component_id, ['access', 'login']) && in_array($component['type'], ['timestamp', 'timestamp_ago'])) { + $component['type'] = 'user_' . $component['type']; + $display->setComponent($component_id, $component); + $changed = TRUE; + } + } + if ($changed) { + $display->save(); + } + } + } + + // Update views. + foreach ($config_factory->listAll('views.view.') as $name) { + $changed = FALSE; + $view = $config_factory->getEditable($name); + $displays = $view->get('display') ?: []; + foreach ($displays as $display_name => $display) { + $fields = $view->get("display.{$display_name}.display_options.fields") ?: []; + foreach ($fields as $field_name => $field) { + if (in_array($field_name, ['access', 'login']) && $field['table'] == 'users_field_data') { + if (in_array($field['type'], ['timestamp', 'timestamp_ago'])) { + $view->set("display.{$display_name}.display_options.fields.{$field_name}.type", "user_{$field['type']}"); + $changed = TRUE; + } + } + } + } + if ($changed) { + $view->save(); + } + } +}