Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  
   3  namespace Sabberworm\CSS;
   4  
   5  use Sabberworm\CSS\Parsing\OutputException;
   6  
   7  class OutputFormatter
   8  {
   9      /**
  10       * @var OutputFormat
  11       */
  12      private $oFormat;
  13  
  14      public function __construct(OutputFormat $oFormat)
  15      {
  16          $this->oFormat = $oFormat;
  17      }
  18  
  19      /**
  20       * @param string $sName
  21       * @param string|null $sType
  22       *
  23       * @return string
  24       */
  25      public function space($sName, $sType = null)
  26      {
  27          $sSpaceString = $this->oFormat->get("Space$sName");
  28          // If $sSpaceString is an array, we have multiple values configured
  29          // depending on the type of object the space applies to
  30          if (is_array($sSpaceString)) {
  31              if ($sType !== null && isset($sSpaceString[$sType])) {
  32                  $sSpaceString = $sSpaceString[$sType];
  33              } else {
  34                  $sSpaceString = reset($sSpaceString);
  35              }
  36          }
  37          return $this->prepareSpace($sSpaceString);
  38      }
  39  
  40      /**
  41       * @return string
  42       */
  43      public function spaceAfterRuleName()
  44      {
  45          return $this->space('AfterRuleName');
  46      }
  47  
  48      /**
  49       * @return string
  50       */
  51      public function spaceBeforeRules()
  52      {
  53          return $this->space('BeforeRules');
  54      }
  55  
  56      /**
  57       * @return string
  58       */
  59      public function spaceAfterRules()
  60      {
  61          return $this->space('AfterRules');
  62      }
  63  
  64      /**
  65       * @return string
  66       */
  67      public function spaceBetweenRules()
  68      {
  69          return $this->space('BetweenRules');
  70      }
  71  
  72      /**
  73       * @return string
  74       */
  75      public function spaceBeforeBlocks()
  76      {
  77          return $this->space('BeforeBlocks');
  78      }
  79  
  80      /**
  81       * @return string
  82       */
  83      public function spaceAfterBlocks()
  84      {
  85          return $this->space('AfterBlocks');
  86      }
  87  
  88      /**
  89       * @return string
  90       */
  91      public function spaceBetweenBlocks()
  92      {
  93          return $this->space('BetweenBlocks');
  94      }
  95  
  96      /**
  97       * @return string
  98       */
  99      public function spaceBeforeSelectorSeparator()
 100      {
 101          return $this->space('BeforeSelectorSeparator');
 102      }
 103  
 104      /**
 105       * @return string
 106       */
 107      public function spaceAfterSelectorSeparator()
 108      {
 109          return $this->space('AfterSelectorSeparator');
 110      }
 111  
 112      /**
 113       * @param string $sSeparator
 114       *
 115       * @return string
 116       */
 117      public function spaceBeforeListArgumentSeparator($sSeparator)
 118      {
 119          return $this->space('BeforeListArgumentSeparator', $sSeparator);
 120      }
 121  
 122      /**
 123       * @param string $sSeparator
 124       *
 125       * @return string
 126       */
 127      public function spaceAfterListArgumentSeparator($sSeparator)
 128      {
 129          return $this->space('AfterListArgumentSeparator', $sSeparator);
 130      }
 131  
 132      /**
 133       * @return string
 134       */
 135      public function spaceBeforeOpeningBrace()
 136      {
 137          return $this->space('BeforeOpeningBrace');
 138      }
 139  
 140      /**
 141       * Runs the given code, either swallowing or passing exceptions, depending on the `bIgnoreExceptions` setting.
 142       *
 143       * @param string $cCode the name of the function to call
 144       *
 145       * @return string|null
 146       */
 147      public function safely($cCode)
 148      {
 149          if ($this->oFormat->get('IgnoreExceptions')) {
 150              // If output exceptions are ignored, run the code with exception guards
 151              try {
 152                  return $cCode();
 153              } catch (OutputException $e) {
 154                  return null;
 155              } // Do nothing
 156          } else {
 157              // Run the code as-is
 158              return $cCode();
 159          }
 160      }
 161  
 162      /**
 163       * Clone of the `implode` function, but calls `render` with the current output format instead of `__toString()`.
 164       *
 165       * @param string $sSeparator
 166       * @param array<array-key, Renderable|string> $aValues
 167       * @param bool $bIncreaseLevel
 168       *
 169       * @return string
 170       */
 171      public function implode($sSeparator, array $aValues, $bIncreaseLevel = false)
 172      {
 173          $sResult = '';
 174          $oFormat = $this->oFormat;
 175          if ($bIncreaseLevel) {
 176              $oFormat = $oFormat->nextLevel();
 177          }
 178          $bIsFirst = true;
 179          foreach ($aValues as $mValue) {
 180              if ($bIsFirst) {
 181                  $bIsFirst = false;
 182              } else {
 183                  $sResult .= $sSeparator;
 184              }
 185              if ($mValue instanceof Renderable) {
 186                  $sResult .= $mValue->render($oFormat);
 187              } else {
 188                  $sResult .= $mValue;
 189              }
 190          }
 191          return $sResult;
 192      }
 193  
 194      /**
 195       * @param string $sString
 196       *
 197       * @return string
 198       */
 199      public function removeLastSemicolon($sString)
 200      {
 201          if ($this->oFormat->get('SemicolonAfterLastRule')) {
 202              return $sString;
 203          }
 204          $sString = explode(';', $sString);
 205          if (count($sString) < 2) {
 206              return $sString[0];
 207          }
 208          $sLast = array_pop($sString);
 209          $sNextToLast = array_pop($sString);
 210          array_push($sString, $sNextToLast . $sLast);
 211          return implode(';', $sString);
 212      }
 213  
 214      /**
 215       * @param string $sSpaceString
 216       *
 217       * @return string
 218       */
 219      private function prepareSpace($sSpaceString)
 220      {
 221          return str_replace("\n", "\n" . $this->indent(), $sSpaceString);
 222      }
 223  
 224      /**
 225       * @return string
 226       */
 227      private function indent()
 228      {
 229          return str_repeat($this->oFormat->sIndentation, $this->oFormat->level());
 230      }
 231  }