Commit 0c127c54 authored by catch's avatar catch
Browse files

Issue #2500525 by dawehner, catch, pjonckiere, mpdonadio, Wim Leers, jhodgdon:...

Issue #2500525 by dawehner, catch, pjonckiere, mpdonadio, Wim Leers, jhodgdon: Time ago/hence date/time formatting breaks caching; needs appropriate max age or javascript
parent 85489825
......@@ -206,10 +206,15 @@ public function formatDiff($from, $to, $options = array()) {
'granularity' => 2,
'langcode' => NULL,
'strict' => TRUE,
'return_as_object' => FALSE,
);
if ($options['strict'] && $from > $to) {
return $this->t('0 seconds');
$string = $this->t('0 seconds');
if ($options['return_as_object']) {
return new FormattedDateDiff($string, 0);
}
return $string;
}
$date_time_from = new \DateTime();
......@@ -226,6 +231,7 @@ public function formatDiff($from, $to, $options = array()) {
// We loop over the keys provided by \DateInterval explicitly. Since we
// don't take the "invert" property into account, the resulting output value
// will always be positive.
$max_age = 1e99;
foreach (array('y', 'm', 'd', 'h', 'i', 's') as $value) {
if ($interval->$value > 0) {
// Switch over the keys to call formatPlural() explicitly with literal
......@@ -233,10 +239,12 @@ public function formatDiff($from, $to, $options = array()) {
switch ($value) {
case 'y':
$interval_output = $this->formatPlural($interval->y, '1 year', '@count years', array(), array('langcode' => $options['langcode']));
$max_age = min($max_age, 365*86400);
break;
case 'm':
$interval_output = $this->formatPlural($interval->m, '1 month', '@count months', array(), array('langcode' => $options['langcode']));
$max_age = min($max_age, 30*86400);
break;
case 'd':
......@@ -249,10 +257,12 @@ public function formatDiff($from, $to, $options = array()) {
$interval_output .= $this->formatPlural($weeks, '1 week', '@count weeks', array(), array('langcode' => $options['langcode']));
$days -= $weeks * 7;
$granularity--;
$max_age = min($max_age, 7*86400);
}
if ((!$output || $weeks > 0) && $granularity > 0 && $days > 0) {
$interval_output .= ($interval_output ? ' ' : '') . $this->formatPlural($days, '1 day', '@count days', array(), array('langcode' => $options['langcode']));
$max_age = min($max_age, 86400);
}
else {
// If we did not output days, set the granularity to 0 so that we
......@@ -263,14 +273,17 @@ public function formatDiff($from, $to, $options = array()) {
case 'h':
$interval_output = $this->formatPlural($interval->h, '1 hour', '@count hours', array(), array('langcode' => $options['langcode']));
$max_age = min($max_age, 3600);
break;
case 'i':
$interval_output = $this->formatPlural($interval->i, '1 minute', '@count minutes', array(), array('langcode' => $options['langcode']));
$max_age = min($max_age, 60);
break;
case 's':
$interval_output = $this->formatPlural($interval->s, '1 second', '@count seconds', array(), array('langcode' => $options['langcode']));
$max_age = min($max_age, 1);
break;
}
......@@ -290,6 +303,11 @@ public function formatDiff($from, $to, $options = array()) {
if (empty($output)) {
$output = $this->t('0 seconds');
$max_age = 0;
}
if ($options['return_as_object']) {
return new FormattedDateDiff($output, $max_age);
}
return $output;
......
......@@ -107,8 +107,10 @@ public function getSampleDateFormats($langcode = NULL, $timestamp = NULL, $timez
* before the current request time, the result string will be "0 seconds".
* If FALSE and $timestamp is before the current request time, the result
* string will be the formatted time difference.
* - return_as_object: A Boolean value whether to return a FormattedDateDiff
* object.
*
* @return string
* @return string|\Drupal\Core\Datetime\FormattedDateDiff
* A translated string representation of the difference between the given
* timestamp and the current request time. This interval is always positive.
*
......@@ -135,8 +137,10 @@ public function formatTimeDiffUntil($timestamp, $options = array());
* after the current request time, the result string will be "0 seconds".
* If FALSE and $timestamp is after the current request time, the result
* string will be the formatted time difference.
* - return_as_object: A Boolean value whether to return a FormattedDateDiff
* object.
*
* @return string
* @return string|\Drupal\Core\Datetime\FormattedDateDiff
* A translated string representation of the difference between the given
* timestamp and the current request time. This interval is always positive.
*
......@@ -164,8 +168,10 @@ public function formatTimeDiffSince($timestamp, $options = array());
* can be after the $to timestamp. If TRUE (default) and $from is after
* $to, the result string will be "0 seconds". If FALSE and $from is
* after $to, the result string will be the formatted time difference.
* - return_as_object: A Boolean value whether to return a FormattedDateDiff
* object.
*
* @return string
* @return string|\Drupal\Core\Datetime\FormattedDateDiff
* A translated string representation of the interval. This interval is
* always positive.
*
......
<?php
/**
* @file
* Contains \Drupal\Core\Datetime\FormattedDateDiff.
*/
namespace Drupal\Core\Datetime;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Cache\UnchangingCacheableDependencyTrait;
use Drupal\Core\Render\RenderableInterface;
/**
* Contains a formatted time difference.
*/
class FormattedDateDiff implements RenderableInterface, CacheableDependencyInterface {
use UnchangingCacheableDependencyTrait;
/**
* The actual formatted time difference.
*
* @var string
*/
protected $string;
/**
* The maximum time in seconds that this string may be cached.
*
* Let's say the time difference is 1 day 1 hour. In this case, we can cache
* it until now + 1 hour, so maxAge is 3600 seconds.
*
* @var int
*/
protected $maxAge;
/**
* Creates a new FormattedDateDiff instance.
*
* @param string $string
* The formatted time difference.
* @param int $max_age
* The maximum time in seconds that this string may be cached.
*/
public function __construct($string, $max_age) {
$this->string = $string;
$this->maxAge = $max_age;
}
/**
* @return string
*/
public function getString() {
return $this->string;
}
/**
* @return int
*/
public function getMaxAge() {
return $this->maxAge;
}
/**
* {@inheritdoc}
*/
public function toRenderable() {
return [
'#markup' => $this->string,
'#cache' => [
'max-age' => $this->maxAge,
],
];
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\Core\Field\Plugin\Field\FieldFormatter;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
......@@ -161,10 +162,12 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
$updated = $this->formatTimestamp($item->value);
}
else {
$updated = $this->t('never');
$updated = [
'#markup' => $this->t('never'),
];
}
$elements[$delta] = array('#markup' => $updated);
$elements[$delta] = $updated;
}
return $elements;
......@@ -176,19 +179,30 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
* @param int $timestamp
* A UNIX timestamp to format.
*
* @return string
* @return array
* The formatted timestamp string using the past or future format setting.
*/
protected function formatTimestamp($timestamp) {
$granularity = $this->getSetting('granularity');
$options = ['granularity' => $granularity];
$options = [
'granularity' => $granularity,
'return_as_object' => TRUE,
];
if ($this->request->server->get('REQUEST_TIME') > $timestamp) {
return SafeMarkup::format($this->getSetting('past_format'), ['@interval' => $this->dateFormatter->formatTimeDiffSince($timestamp, $options)]);
$result = $this->dateFormatter->formatTimeDiffSince($timestamp, $options);
$build = [
'#markup' => SafeMarkup::format($this->getSetting('past_format'), ['@interval' => $result->getString()]),
];
}
else {
return SafeMarkup::format($this->getSetting('future_format'), ['@interval' => $this->dateFormatter->formatTimeDiffUntil($timestamp, $options)]);
$result = $this->dateFormatter->formatTimeDiffUntil($timestamp, $options);
$build = [
'#markup' => SafeMarkup::format($this->getSetting('future_format'), ['@interval' => $result->getString()]),
];
}
CacheableMetadata::createFromObject($result)->applyTo($build);
return $build;
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\datetime\Plugin\Field\FieldFormatter;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldDefinitionInterface;
......@@ -112,7 +113,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
foreach ($items as $delta => $item) {
$date = $item->date;
$output = '';
$output = [];
if (!empty($item->date)) {
if ($this->getFieldSetting('datetime_type') == 'date') {
// A date without time will pick up the current time, use the default.
......@@ -120,7 +121,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
}
$output = $this->formatDate($date);
}
$elements[$delta] = array('#markup' => $output);
$elements[$delta] = $output;
}
return $elements;
......@@ -176,20 +177,31 @@ public function settingsSummary() {
* @param \Drupal\Core\Datetime\DrupalDateTime|object $date
* A date/time object.
*
* @return string
* @return array
* The formatted date/time string using the past or future format setting.
*/
protected function formatDate(DrupalDateTime $date) {
$granularity = $this->getSetting('granularity');
$timestamp = $date->getTimestamp();
$options = ['granularity' => $granularity];
$options = [
'granularity' => $granularity,
'return_as_object' => TRUE,
];
if ($this->request->server->get('REQUEST_TIME') > $timestamp) {
return SafeMarkup::format($this->getSetting('past_format'), ['@interval' => $this->dateFormatter->formatTimeDiffSince($timestamp, $options)]);
$result = $this->dateFormatter->formatTimeDiffSince($timestamp, $options);
$build = [
'#markup' => SafeMarkup::format($this->getSetting('past_format'), ['@interval' => $result->getString()]),
];
}
else {
return SafeMarkup::format($this->getSetting('future_format'), ['@interval' => $this->dateFormatter->formatTimeDiffUntil($timestamp, $options)]);
$result = $this->dateFormatter->formatTimeDiffUntil($timestamp, $options);
$build = [
'#markup' => SafeMarkup::format($this->getSetting('future_format'), ['@interval' => $result->getString()]),
];
}
CacheableMetadata::createFromObject($result)->applyTo($build);
return $build;
}
}
......@@ -7,6 +7,7 @@
namespace Drupal\user;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityListBuilder;
......@@ -151,8 +152,19 @@ public function buildRow(EntityInterface $entity) {
'#theme' => 'item_list',
'#items' => $users_roles,
);
$row['member_for'] = $this->dateFormatter->formatTimeDiffSince($entity->getCreatedTime());
$row['access'] = $entity->access ? $this->t('@time ago', array('@time' => $this->dateFormatter->formatTimeDiffSince($entity->getLastAccessedTime()))) : t('never');
$options = [
'return_as_object' => TRUE,
];
$row['member_for']['data'] = $this->dateFormatter->formatTimeDiffSince($entity->getCreatedTime(), $options)->toRenderable();
$last_access = $this->dateFormatter->formatTimeDiffSince($entity->getLastAccessedTime(), $options);
if ($entity->access) {
$row['access']['data']['#markup'] = $last_access->getString();
CacheableMetadata::createFromObject($last_access)->applyTo($row['access']['data']);
}
else {
$row['access']['data']['#markup'] = t('never');
}
return $row + parent::buildRow($entity);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment