Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;
   4  
   5  class Duration extends DateTimeWizard
   6  {
   7      public const DAYS_DURATION = 'd';
   8  
   9      /**
  10       * Hours as a duration (can exceed 24), e.g. 29.
  11       */
  12      public const HOURS_DURATION = '[h]';
  13  
  14      /**
  15       * Hours without a leading zero, e.g. 9.
  16       */
  17      public const HOURS_SHORT = 'h';
  18  
  19      /**
  20       * Hours with a leading zero, e.g. 09.
  21       */
  22      public const HOURS_LONG = 'hh';
  23  
  24      /**
  25       * Minutes as a duration (can exceed 60), e.g. 109.
  26       */
  27      public const MINUTES_DURATION = '[m]';
  28  
  29      /**
  30       * Minutes without a leading zero, e.g. 5.
  31       */
  32      public const MINUTES_SHORT = 'm';
  33  
  34      /**
  35       * Minutes with a leading zero, e.g. 05.
  36       */
  37      public const MINUTES_LONG = 'mm';
  38  
  39      /**
  40       * Seconds as a duration (can exceed 60), e.g. 129.
  41       */
  42      public const SECONDS_DURATION = '[s]';
  43  
  44      /**
  45       * Seconds without a leading zero, e.g. 2.
  46       */
  47      public const SECONDS_SHORT = 's';
  48  
  49      /**
  50       * Seconds with a leading zero, e.g. 02.
  51       */
  52      public const SECONDS_LONG = 'ss';
  53  
  54      protected const DURATION_BLOCKS = [
  55          self::DAYS_DURATION,
  56          self::HOURS_DURATION,
  57          self::HOURS_LONG,
  58          self::HOURS_SHORT,
  59          self::MINUTES_DURATION,
  60          self::MINUTES_LONG,
  61          self::MINUTES_SHORT,
  62          self::SECONDS_DURATION,
  63          self::SECONDS_LONG,
  64          self::SECONDS_SHORT,
  65      ];
  66  
  67      protected const DURATION_MASKS = [
  68          self::DAYS_DURATION => self::DAYS_DURATION,
  69          self::HOURS_DURATION => self::HOURS_SHORT,
  70          self::MINUTES_DURATION => self::MINUTES_LONG,
  71          self::SECONDS_DURATION => self::SECONDS_LONG,
  72      ];
  73  
  74      protected const DURATION_DEFAULTS = [
  75          self::HOURS_LONG => self::HOURS_DURATION,
  76          self::HOURS_SHORT => self::HOURS_DURATION,
  77          self::MINUTES_LONG => self::MINUTES_DURATION,
  78          self::MINUTES_SHORT => self::MINUTES_DURATION,
  79          self::SECONDS_LONG => self::SECONDS_DURATION,
  80          self::SECONDS_SHORT => self::SECONDS_DURATION,
  81      ];
  82  
  83      public const SEPARATOR_COLON = ':';
  84      public const SEPARATOR_SPACE_NONBREAKING = "\u{a0}";
  85      public const SEPARATOR_SPACE = ' ';
  86  
  87      public const DURATION_DEFAULT = [
  88          self::HOURS_DURATION,
  89          self::MINUTES_LONG,
  90          self::SECONDS_LONG,
  91      ];
  92  
  93      /**
  94       * @var string[]
  95       */
  96      protected array $separators;
  97  
  98      /**
  99       * @var string[]
 100       */
 101      protected array $formatBlocks;
 102  
 103      protected bool $durationIsSet = false;
 104  
 105      /**
 106       * @param null|string|string[] $separators
 107       *        If you want to use the same separator for all format blocks, then it can be passed as a string literal;
 108       *           if you wish to use different separators, then they should be passed as an array.
 109       *        If you want to use only a single format block, then pass a null as the separator argument
 110       */
 111      public function __construct($separators = self::SEPARATOR_COLON, string ...$formatBlocks)
 112      {
 113          $separators ??= self::SEPARATOR_COLON;
 114          $formatBlocks = (count($formatBlocks) === 0) ? self::DURATION_DEFAULT : $formatBlocks;
 115  
 116          $this->separators = $this->padSeparatorArray(
 117              is_array($separators) ? $separators : [$separators],
 118              count($formatBlocks) - 1
 119          );
 120          $this->formatBlocks = array_map([$this, 'mapFormatBlocks'], $formatBlocks);
 121  
 122          if ($this->durationIsSet === false) {
 123              // We need at least one duration mask, so if none has been set we change the first mask element
 124              //    to a duration.
 125              $this->formatBlocks[0] = self::DURATION_DEFAULTS[mb_strtolower($this->formatBlocks[0])];
 126          }
 127      }
 128  
 129      private function mapFormatBlocks(string $value): string
 130      {
 131          // Any duration masking codes are returned as lower case values
 132          if (in_array(mb_strtolower($value), self::DURATION_BLOCKS, true)) {
 133              if (array_key_exists(mb_strtolower($value), self::DURATION_MASKS)) {
 134                  if ($this->durationIsSet) {
 135                      // We should only have a single duration mask, the first defined in the mask set,
 136                      //    so convert any additional duration masks to standard time masks.
 137                      $value = self::DURATION_MASKS[mb_strtolower($value)];
 138                  }
 139                  $this->durationIsSet = true;
 140              }
 141  
 142              return mb_strtolower($value);
 143          }
 144  
 145          // Wrap any string literals in quotes, so that they're clearly defined as string literals
 146          return $this->wrapLiteral($value);
 147      }
 148  
 149      public function format(): string
 150      {
 151          return implode('', array_map([$this, 'intersperse'], $this->formatBlocks, $this->separators));
 152      }
 153  }