Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet;
   4  
   5  use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
   6  
   7  abstract class DefinedName
   8  {
   9      protected const REGEXP_IDENTIFY_FORMULA = '[^_\p{N}\p{L}:, \$\'!]';
  10  
  11      /**
  12       * Name.
  13       *
  14       * @var string
  15       */
  16      protected $name;
  17  
  18      /**
  19       * Worksheet on which the defined name can be resolved.
  20       *
  21       * @var Worksheet
  22       */
  23      protected $worksheet;
  24  
  25      /**
  26       * Value of the named object.
  27       *
  28       * @var string
  29       */
  30      protected $value;
  31  
  32      /**
  33       * Is the defined named local? (i.e. can only be used on $this->worksheet).
  34       *
  35       * @var bool
  36       */
  37      protected $localOnly;
  38  
  39      /**
  40       * Scope.
  41       *
  42       * @var Worksheet
  43       */
  44      protected $scope;
  45  
  46      /**
  47       * Whether this is a named range or a named formula.
  48       *
  49       * @var bool
  50       */
  51      protected $isFormula;
  52  
  53      /**
  54       * Create a new Defined Name.
  55       */
  56      public function __construct(
  57          string $name,
  58          ?Worksheet $worksheet = null,
  59          ?string $value = null,
  60          bool $localOnly = false,
  61          ?Worksheet $scope = null
  62      ) {
  63          if ($worksheet === null) {
  64              $worksheet = $scope;
  65          }
  66  
  67          // Set local members
  68          $this->name = $name;
  69          $this->worksheet = $worksheet;
  70          $this->value = (string) $value;
  71          $this->localOnly = $localOnly;
  72          // If local only, then the scope will be set to worksheet unless a scope is explicitly set
  73          $this->scope = ($localOnly === true) ? (($scope === null) ? $worksheet : $scope) : null;
  74          // If the range string contains characters that aren't associated with the range definition (A-Z,1-9
  75          //      for cell references, and $, or the range operators (colon comma or space), quotes and ! for
  76          //      worksheet names
  77          //  then this is treated as a named formula, and not a named range
  78          $this->isFormula = self::testIfFormula($this->value);
  79      }
  80  
  81      /**
  82       * Create a new defined name, either a range or a formula.
  83       */
  84      public static function createInstance(
  85          string $name,
  86          ?Worksheet $worksheet = null,
  87          ?string $value = null,
  88          bool $localOnly = false,
  89          ?Worksheet $scope = null
  90      ): self {
  91          $value = (string) $value;
  92          $isFormula = self::testIfFormula($value);
  93          if ($isFormula) {
  94              return new NamedFormula($name, $worksheet, $value, $localOnly, $scope);
  95          }
  96  
  97          return new NamedRange($name, $worksheet, $value, $localOnly, $scope);
  98      }
  99  
 100      public static function testIfFormula(string $value): bool
 101      {
 102          if (substr($value, 0, 1) === '=') {
 103              $value = substr($value, 1);
 104          }
 105  
 106          if (is_numeric($value)) {
 107              return true;
 108          }
 109  
 110          $segMatcher = false;
 111          foreach (explode("'", $value) as $subVal) {
 112              //    Only test in alternate array entries (the non-quoted blocks)
 113              if (
 114                  ($segMatcher = !$segMatcher) &&
 115                  (preg_match('/' . self::REGEXP_IDENTIFY_FORMULA . '/miu', $subVal))
 116              ) {
 117                  return true;
 118              }
 119          }
 120  
 121          return false;
 122      }
 123  
 124      /**
 125       * Get name.
 126       */
 127      public function getName(): string
 128      {
 129          return $this->name;
 130      }
 131  
 132      /**
 133       * Set name.
 134       */
 135      public function setName(string $name): self
 136      {
 137          if (!empty($name)) {
 138              // Old title
 139              $oldTitle = $this->name;
 140  
 141              // Re-attach
 142              if ($this->worksheet !== null) {
 143                  $this->worksheet->getParent()->removeNamedRange($this->name, $this->worksheet);
 144              }
 145              $this->name = $name;
 146  
 147              if ($this->worksheet !== null) {
 148                  $this->worksheet->getParent()->addNamedRange($this);
 149              }
 150  
 151              // New title
 152              $newTitle = $this->name;
 153              ReferenceHelper::getInstance()->updateNamedFormulas($this->worksheet->getParent(), $oldTitle, $newTitle);
 154          }
 155  
 156          return $this;
 157      }
 158  
 159      /**
 160       * Get worksheet.
 161       */
 162      public function getWorksheet(): ?Worksheet
 163      {
 164          return $this->worksheet;
 165      }
 166  
 167      /**
 168       * Set worksheet.
 169       */
 170      public function setWorksheet(?Worksheet $value): self
 171      {
 172          $this->worksheet = $value;
 173  
 174          return $this;
 175      }
 176  
 177      /**
 178       * Get range or formula value.
 179       */
 180      public function getValue(): string
 181      {
 182          return $this->value;
 183      }
 184  
 185      /**
 186       * Set range or formula  value.
 187       */
 188      public function setValue(string $value): self
 189      {
 190          $this->value = $value;
 191  
 192          return $this;
 193      }
 194  
 195      /**
 196       * Get localOnly.
 197       */
 198      public function getLocalOnly(): bool
 199      {
 200          return $this->localOnly;
 201      }
 202  
 203      /**
 204       * Set localOnly.
 205       */
 206      public function setLocalOnly(bool $value): self
 207      {
 208          $this->localOnly = $value;
 209          $this->scope = $value ? $this->worksheet : null;
 210  
 211          return $this;
 212      }
 213  
 214      /**
 215       * Get scope.
 216       */
 217      public function getScope(): ?Worksheet
 218      {
 219          return $this->scope;
 220      }
 221  
 222      /**
 223       * Set scope.
 224       */
 225      public function setScope(?Worksheet $value): self
 226      {
 227          $this->scope = $value;
 228          $this->localOnly = $value !== null;
 229  
 230          return $this;
 231      }
 232  
 233      /**
 234       * Identify whether this is a named range or a named formula.
 235       */
 236      public function isFormula(): bool
 237      {
 238          return $this->isFormula;
 239      }
 240  
 241      /**
 242       * Resolve a named range to a regular cell range or formula.
 243       */
 244      public static function resolveName(string $pDefinedName, Worksheet $pSheet): ?self
 245      {
 246          return $pSheet->getParent()->getDefinedName($pDefinedName, $pSheet);
 247      }
 248  
 249      /**
 250       * Implement PHP __clone to create a deep clone, not just a shallow copy.
 251       */
 252      public function __clone()
 253      {
 254          $vars = get_object_vars($this);
 255          foreach ($vars as $key => $value) {
 256              if (is_object($value)) {
 257                  $this->$key = clone $value;
 258              } else {
 259                  $this->$key = $value;
 260              }
 261          }
 262      }
 263  }