DrupalDateTime.php 4.7 KB
Newer Older
1 2 3 4 5 6 7 8 9
<?php

/**
 * @file
 * Definition of Drupal\Core\Datetime\DrupalDateTime.
 */
namespace Drupal\Core\Datetime;

use Drupal\Component\Datetime\DateTimePlus;
10
use Drupal\Core\StringTranslation\StringTranslationTrait;
11 12 13 14 15 16 17

/**
 * Extends DateTimePlus().
 *
 * This class extends the basic component and adds in Drupal-specific
 * handling, like translation of the format() method.
 *
18 19 20 21 22
 * Static methods in base class can also be used to create DrupalDateTime objects.
 * For example:
 *
 * DrupalDateTime::createFromArray( array('year' => 2010, 'month' => 9, 'day' => 28) )
 *
23
 * @see \Drupal/Component/Datetime/DateTimePlus.php
24 25 26
 */
class DrupalDateTime extends DateTimePlus {

27 28 29 30 31 32 33 34
  use StringTranslationTrait;

  /**
   * Format string translation cache.
   *
   */
  protected $formatTranslationCache;

35 36 37
  /**
   * Constructs a date object.
   *
38 39
   * @param string $time
   *   A DateTime object, a date/input_time_adjusted string, a unix timestamp.
40 41 42 43 44 45 46 47 48 49 50 51
   *   Defaults to 'now'.
   * @param mixed $timezone
   *   PHP DateTimeZone object, string or NULL allowed.
   *   Defaults to NULL.
   * @param array $settings
   *   - validate_format: (optional) Boolean choice to validate the
   *     created date using the input format. The format used in
   *     createFromFormat() allows slightly different values than format().
   *     Using an input format that works in both functions makes it
   *     possible to a validation step to confirm that the date created
   *     from a format string exactly matches the input. This option
   *     indicates the format can be used for validation. Defaults to TRUE.
52
   *   - langcode: (optional) Used to control the result of the format() method.
53 54 55 56
   *     Defaults to NULL.
   *   - debug: (optional) Boolean choice to leave debug values in the
   *     date object for debugging purposes. Defaults to FALSE.
   */
57 58
  public function __construct($time = 'now', $timezone = NULL, $settings = array()) {
    if (!isset($settings['langcode'])) {
59
      $settings['langcode'] = \Drupal::languageManager()->getCurrentLanguage()->getId();
60 61
    }

62
    // Instantiate the parent class.
63
    parent::__construct($time, $timezone, $settings);
64 65 66 67 68 69 70 71 72 73

  }

  /**
   * Overrides prepareTimezone().
   *
   * Override basic component timezone handling to use Drupal's
   * knowledge of the preferred user timezone.
   */
  protected function prepareTimezone($timezone) {
74 75 76
    if (empty($timezone)) {
      // Fallback to user or system default timezone.
      $timezone = drupal_get_user_timezone();
77
    }
78
    return parent::prepareTimezone($timezone);
79 80 81 82 83 84
  }

  /**
   * Overrides format().
   *
   * @param string $format
85
   *   A format string using either PHP's date().
86 87 88
   * @param array $settings
   *   - timezone: (optional) String timezone name. Defaults to the timezone
   *     of the date object.
89 90
   *   - langcode: (optional) String two letter language code used to control
   *     the result of the format() method. Defaults to NULL.
91 92 93 94 95
   *
   * @return string
   *   The formatted value of the date.
   */
  public function format($format, $settings = array()) {
96 97
    $langcode = !empty($settings['langcode']) ? $settings['langcode'] : $this->langcode;
    $value = '';
98 99
    // Format the date and catch errors.
    try {
100 101 102 103 104 105 106 107 108
      // Encode markers that should be translated. 'A' becomes
      // '\xEF\AA\xFF'. xEF and xFF are invalid UTF-8 sequences,
      // and we assume they are not in the input string.
      // Paired backslashes are isolated to prevent errors in
      // read-ahead evaluation. The read-ahead expression ensures that
      // A matches, but not \A.
      $format = preg_replace(array('/\\\\\\\\/', '/(?<!\\\\)([AaeDlMTF])/'), array("\xEF\\\\\\\\\xFF", "\xEF\\\\\$1\$1\xFF"), $format);

      // Call date_format().
109
      $format = parent::format($format, $settings);
110

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
      // Translates a formatted date string.
      $translation_callback = function($matches) use ($langcode) {
        $code = $matches[1];
        $string = $matches[2];
        if (!isset($this->formatTranslationCache[$langcode][$code][$string])) {
          $options = array('langcode' => $langcode);
          if ($code == 'F') {
            $options['context'] = 'Long month name';
          }

          if ($code == '') {
            $this->formatTranslationCache[$langcode][$code][$string] = $string;
          }
          else {
            $this->formatTranslationCache[$langcode][$code][$string] = $this->t($string, array(), $options);
          }
        }
        return $this->formatTranslationCache[$langcode][$code][$string];
      };
130 131

      // Translate the marked sequences.
132
      $value = preg_replace_callback('/\xEF([AaeDlMTF]?)(.*?)\xFF/', $translation_callback, $format);
133 134 135 136 137 138
    }
    catch (\Exception $e) {
      $this->errors[] = $e->getMessage();
    }
    return $value;
  }
139

140
}