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.

Differences Between: [Versions 401 and 403]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\Wizard;
   4  
   5  use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
   6  use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
   7  use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\Wizard;
   8  use PhpOffice\PhpSpreadsheet\Style\Style;
   9  
  10  abstract class WizardAbstract
  11  {
  12      /**
  13       * @var ?Style
  14       */
  15      protected $style;
  16  
  17      /**
  18       * @var string
  19       */
  20      protected $expression;
  21  
  22      /**
  23       * @var string
  24       */
  25      protected $cellRange;
  26  
  27      /**
  28       * @var string
  29       */
  30      protected $referenceCell;
  31  
  32      /**
  33       * @var int
  34       */
  35      protected $referenceRow;
  36  
  37      /**
  38       * @var bool
  39       */
  40      protected $stopIfTrue = false;
  41  
  42      /**
  43       * @var int
  44       */
  45      protected $referenceColumn;
  46  
  47      public function __construct(string $cellRange)
  48      {
  49          $this->setCellRange($cellRange);
  50      }
  51  
  52      public function getCellRange(): string
  53      {
  54          return $this->cellRange;
  55      }
  56  
  57      public function setCellRange(string $cellRange): void
  58      {
  59          $this->cellRange = $cellRange;
  60          $this->setReferenceCellForExpressions($cellRange);
  61      }
  62  
  63      protected function setReferenceCellForExpressions(string $conditionalRange): void
  64      {
  65          $conditionalRange = Coordinate::splitRange(str_replace('$', '', strtoupper($conditionalRange)));
  66          [$this->referenceCell] = $conditionalRange[0];
  67  
  68          [$this->referenceColumn, $this->referenceRow] = Coordinate::indexesFromString($this->referenceCell);
  69      }
  70  
  71      public function getStopIfTrue(): bool
  72      {
  73          return $this->stopIfTrue;
  74      }
  75  
  76      public function setStopIfTrue(bool $stopIfTrue): void
  77      {
  78          $this->stopIfTrue = $stopIfTrue;
  79      }
  80  
  81      public function getStyle(): Style
  82      {
  83          return $this->style ?? new Style(false, true);
  84      }
  85  
  86      public function setStyle(Style $style): void
  87      {
  88          $this->style = $style;
  89      }
  90  
  91      protected function validateOperand(string $operand, string $operandValueType = Wizard::VALUE_TYPE_LITERAL): string
  92      {
  93          if (
  94              $operandValueType === Wizard::VALUE_TYPE_LITERAL &&
  95              substr($operand, 0, 1) === '"' &&
  96              substr($operand, -1) === '"'
  97          ) {
  98              $operand = str_replace('""', '"', substr($operand, 1, -1));
  99          } elseif ($operandValueType === Wizard::VALUE_TYPE_FORMULA && substr($operand, 0, 1) === '=') {
 100              $operand = substr($operand, 1);
 101          }
 102  
 103          return $operand;
 104      }
 105  
 106      protected static function reverseCellAdjustment(array $matches, int $referenceColumn, int $referenceRow): string
 107      {
 108          $worksheet = $matches[1];
 109          $column = $matches[6];
 110          $row = $matches[7];
 111  
 112          if (strpos($column, '$') === false) {
 113              $column = Coordinate::columnIndexFromString($column);
 114              $column -= $referenceColumn - 1;
 115              $column = Coordinate::stringFromColumnIndex($column);
 116          }
 117  
 118          if (strpos($row, '$') === false) {
 119              $row -= $referenceRow - 1;
 120          }
 121  
 122          return "{$worksheet}{$column}{$row}";
 123      }
 124  
 125      public static function reverseAdjustCellRef(string $condition, string $cellRange): string
 126      {
 127          $conditionalRange = Coordinate::splitRange(str_replace('$', '', strtoupper($cellRange)));
 128          [$referenceCell] = $conditionalRange[0];
 129          [$referenceColumnIndex, $referenceRow] = Coordinate::indexesFromString($referenceCell);
 130  
 131          $splitCondition = explode(Calculation::FORMULA_STRING_QUOTE, $condition);
 132          $i = false;
 133          foreach ($splitCondition as &$value) {
 134              //    Only count/replace in alternating array entries (ie. not in quoted strings)
 135              $i = $i === false;
 136              if ($i) {
 137                  $value = (string) preg_replace_callback(
 138                      '/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/i',
 139                      function ($matches) use ($referenceColumnIndex, $referenceRow) {
 140                          return self::reverseCellAdjustment($matches, $referenceColumnIndex, $referenceRow);
 141                      },
 142                      $value
 143                  );
 144              }
 145          }
 146          unset($value);
 147  
 148          //    Then rebuild the condition string to return it
 149          return implode(Calculation::FORMULA_STRING_QUOTE, $splitCondition);
 150      }
 151  
 152      protected function conditionCellAdjustment(array $matches): string
 153      {
 154          $worksheet = $matches[1];
 155          $column = $matches[6];
 156          $row = $matches[7];
 157  
 158          if (strpos($column, '$') === false) {
 159              $column = Coordinate::columnIndexFromString($column);
 160              $column += $this->referenceColumn - 1;
 161              $column = Coordinate::stringFromColumnIndex($column);
 162          }
 163  
 164          if (strpos($row, '$') === false) {
 165              $row += $this->referenceRow - 1;
 166          }
 167  
 168          return "{$worksheet}{$column}{$row}";
 169      }
 170  
 171      protected function cellConditionCheck(string $condition): string
 172      {
 173          $splitCondition = explode(Calculation::FORMULA_STRING_QUOTE, $condition);
 174          $i = false;
 175          foreach ($splitCondition as &$value) {
 176              //    Only count/replace in alternating array entries (ie. not in quoted strings)
 177              $i = $i === false;
 178              if ($i) {
 179                  $value = (string) preg_replace_callback(
 180                      '/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/i',
 181                      [$this, 'conditionCellAdjustment'],
 182                      $value
 183                  );
 184              }
 185          }
 186          unset($value);
 187  
 188          //    Then rebuild the condition string to return it
 189          return implode(Calculation::FORMULA_STRING_QUOTE, $splitCondition);
 190      }
 191  
 192      protected function adjustConditionsForCellReferences(array $conditions): array
 193      {
 194          return array_map(
 195              [$this, 'cellConditionCheck'],
 196              $conditions
 197          );
 198      }
 199  }