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.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Style;
   4  
   5  use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
   6  
   7  class Alignment extends Supervisor
   8  {
   9      // Horizontal alignment styles
  10      const HORIZONTAL_GENERAL = 'general';
  11      const HORIZONTAL_LEFT = 'left';
  12      const HORIZONTAL_RIGHT = 'right';
  13      const HORIZONTAL_CENTER = 'center';
  14      const HORIZONTAL_CENTER_CONTINUOUS = 'centerContinuous';
  15      const HORIZONTAL_JUSTIFY = 'justify';
  16      const HORIZONTAL_FILL = 'fill';
  17      const HORIZONTAL_DISTRIBUTED = 'distributed'; // Excel2007 only
  18      private const HORIZONTAL_CENTER_CONTINUOUS_LC = 'centercontinuous';
  19      // Mapping for horizontal alignment
  20      const HORIZONTAL_ALIGNMENT_FOR_XLSX = [
  21          self::HORIZONTAL_LEFT => self::HORIZONTAL_LEFT,
  22          self::HORIZONTAL_RIGHT => self::HORIZONTAL_RIGHT,
  23          self::HORIZONTAL_CENTER => self::HORIZONTAL_CENTER,
  24          self::HORIZONTAL_CENTER_CONTINUOUS => self::HORIZONTAL_CENTER_CONTINUOUS,
  25          self::HORIZONTAL_JUSTIFY => self::HORIZONTAL_JUSTIFY,
  26          self::HORIZONTAL_FILL => self::HORIZONTAL_FILL,
  27          self::HORIZONTAL_DISTRIBUTED => self::HORIZONTAL_DISTRIBUTED,
  28      ];
  29      // Mapping for horizontal alignment CSS
  30      const HORIZONTAL_ALIGNMENT_FOR_HTML = [
  31          self::HORIZONTAL_LEFT => self::HORIZONTAL_LEFT,
  32          self::HORIZONTAL_RIGHT => self::HORIZONTAL_RIGHT,
  33          self::HORIZONTAL_CENTER => self::HORIZONTAL_CENTER,
  34          self::HORIZONTAL_CENTER_CONTINUOUS => self::HORIZONTAL_CENTER,
  35          self::HORIZONTAL_JUSTIFY => self::HORIZONTAL_JUSTIFY,
  36          //self::HORIZONTAL_FILL => self::HORIZONTAL_FILL, // no reasonable equivalent for fill
  37          self::HORIZONTAL_DISTRIBUTED => self::HORIZONTAL_JUSTIFY,
  38      ];
  39  
  40      // Vertical alignment styles
  41      const VERTICAL_BOTTOM = 'bottom';
  42      const VERTICAL_TOP = 'top';
  43      const VERTICAL_CENTER = 'center';
  44      const VERTICAL_JUSTIFY = 'justify';
  45      const VERTICAL_DISTRIBUTED = 'distributed'; // Excel2007 only
  46      // Vertical alignment CSS
  47      private const VERTICAL_BASELINE = 'baseline';
  48      private const VERTICAL_MIDDLE = 'middle';
  49      private const VERTICAL_SUB = 'sub';
  50      private const VERTICAL_SUPER = 'super';
  51      private const VERTICAL_TEXT_BOTTOM = 'text-bottom';
  52      private const VERTICAL_TEXT_TOP = 'text-top';
  53  
  54      // Mapping for vertical alignment
  55      const VERTICAL_ALIGNMENT_FOR_XLSX = [
  56          self::VERTICAL_BOTTOM => self::VERTICAL_BOTTOM,
  57          self::VERTICAL_TOP => self::VERTICAL_TOP,
  58          self::VERTICAL_CENTER => self::VERTICAL_CENTER,
  59          self::VERTICAL_JUSTIFY => self::VERTICAL_JUSTIFY,
  60          self::VERTICAL_DISTRIBUTED => self::VERTICAL_DISTRIBUTED,
  61          // css settings that arent't in sync with Excel
  62          self::VERTICAL_BASELINE => self::VERTICAL_BOTTOM,
  63          self::VERTICAL_MIDDLE => self::VERTICAL_CENTER,
  64          self::VERTICAL_SUB => self::VERTICAL_BOTTOM,
  65          self::VERTICAL_SUPER => self::VERTICAL_TOP,
  66          self::VERTICAL_TEXT_BOTTOM => self::VERTICAL_BOTTOM,
  67          self::VERTICAL_TEXT_TOP => self::VERTICAL_TOP,
  68      ];
  69  
  70      // Mapping for vertical alignment for Html
  71      const VERTICAL_ALIGNMENT_FOR_HTML = [
  72          self::VERTICAL_BOTTOM => self::VERTICAL_BOTTOM,
  73          self::VERTICAL_TOP => self::VERTICAL_TOP,
  74          self::VERTICAL_CENTER => self::VERTICAL_MIDDLE,
  75          self::VERTICAL_JUSTIFY => self::VERTICAL_MIDDLE,
  76          self::VERTICAL_DISTRIBUTED => self::VERTICAL_MIDDLE,
  77          // css settings that arent't in sync with Excel
  78          self::VERTICAL_BASELINE => self::VERTICAL_BASELINE,
  79          self::VERTICAL_MIDDLE => self::VERTICAL_MIDDLE,
  80          self::VERTICAL_SUB => self::VERTICAL_SUB,
  81          self::VERTICAL_SUPER => self::VERTICAL_SUPER,
  82          self::VERTICAL_TEXT_BOTTOM => self::VERTICAL_TEXT_BOTTOM,
  83          self::VERTICAL_TEXT_TOP => self::VERTICAL_TEXT_TOP,
  84      ];
  85  
  86      // Read order
  87      const READORDER_CONTEXT = 0;
  88      const READORDER_LTR = 1;
  89      const READORDER_RTL = 2;
  90  
  91      // Special value for Text Rotation
  92      const TEXTROTATION_STACK_EXCEL = 255;
  93      const TEXTROTATION_STACK_PHPSPREADSHEET = -165; // 90 - 255
  94  
  95      /**
  96       * Horizontal alignment.
  97       *
  98       * @var null|string
  99       */
 100      protected $horizontal = self::HORIZONTAL_GENERAL;
 101  
 102      /**
 103       * Vertical alignment.
 104       *
 105       * @var null|string
 106       */
 107      protected $vertical = self::VERTICAL_BOTTOM;
 108  
 109      /**
 110       * Text rotation.
 111       *
 112       * @var null|int
 113       */
 114      protected $textRotation = 0;
 115  
 116      /**
 117       * Wrap text.
 118       *
 119       * @var bool
 120       */
 121      protected $wrapText = false;
 122  
 123      /**
 124       * Shrink to fit.
 125       *
 126       * @var bool
 127       */
 128      protected $shrinkToFit = false;
 129  
 130      /**
 131       * Indent - only possible with horizontal alignment left and right.
 132       *
 133       * @var int
 134       */
 135      protected $indent = 0;
 136  
 137      /**
 138       * Read order.
 139       *
 140       * @var int
 141       */
 142      protected $readOrder = 0;
 143  
 144      /**
 145       * Create a new Alignment.
 146       *
 147       * @param bool $isSupervisor Flag indicating if this is a supervisor or not
 148       *                                       Leave this value at default unless you understand exactly what
 149       *                                          its ramifications are
 150       * @param bool $isConditional Flag indicating if this is a conditional style or not
 151       *                                       Leave this value at default unless you understand exactly what
 152       *                                          its ramifications are
 153       */
 154      public function __construct($isSupervisor = false, $isConditional = false)
 155      {
 156          // Supervisor?
 157          parent::__construct($isSupervisor);
 158  
 159          if ($isConditional) {
 160              $this->horizontal = null;
 161              $this->vertical = null;
 162              $this->textRotation = null;
 163          }
 164      }
 165  
 166      /**
 167       * Get the shared style component for the currently active cell in currently active sheet.
 168       * Only used for style supervisor.
 169       *
 170       * @return Alignment
 171       */
 172      public function getSharedComponent()
 173      {
 174          /** @var Style */
 175          $parent = $this->parent;
 176  
 177          return $parent->getSharedComponent()->getAlignment();
 178      }
 179  
 180      /**
 181       * Build style array from subcomponents.
 182       *
 183       * @param array $array
 184       *
 185       * @return array
 186       */
 187      public function getStyleArray($array)
 188      {
 189          return ['alignment' => $array];
 190      }
 191  
 192      /**
 193       * Apply styles from array.
 194       *
 195       * <code>
 196       * $spreadsheet->getActiveSheet()->getStyle('B2')->getAlignment()->applyFromArray(
 197       *        [
 198       *            'horizontal'   => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
 199       *            'vertical'     => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
 200       *            'textRotation' => 0,
 201       *            'wrapText'     => TRUE
 202       *        ]
 203       * );
 204       * </code>
 205       *
 206       * @param array $styleArray Array containing style information
 207       *
 208       * @return $this
 209       */
 210      public function applyFromArray(array $styleArray)
 211      {
 212          if ($this->isSupervisor) {
 213              $this->getActiveSheet()->getStyle($this->getSelectedCells())
 214                  ->applyFromArray($this->getStyleArray($styleArray));
 215          } else {
 216              if (isset($styleArray['horizontal'])) {
 217                  $this->setHorizontal($styleArray['horizontal']);
 218              }
 219              if (isset($styleArray['vertical'])) {
 220                  $this->setVertical($styleArray['vertical']);
 221              }
 222              if (isset($styleArray['textRotation'])) {
 223                  $this->setTextRotation($styleArray['textRotation']);
 224              }
 225              if (isset($styleArray['wrapText'])) {
 226                  $this->setWrapText($styleArray['wrapText']);
 227              }
 228              if (isset($styleArray['shrinkToFit'])) {
 229                  $this->setShrinkToFit($styleArray['shrinkToFit']);
 230              }
 231              if (isset($styleArray['indent'])) {
 232                  $this->setIndent($styleArray['indent']);
 233              }
 234              if (isset($styleArray['readOrder'])) {
 235                  $this->setReadOrder($styleArray['readOrder']);
 236              }
 237          }
 238  
 239          return $this;
 240      }
 241  
 242      /**
 243       * Get Horizontal.
 244       *
 245       * @return null|string
 246       */
 247      public function getHorizontal()
 248      {
 249          if ($this->isSupervisor) {
 250              return $this->getSharedComponent()->getHorizontal();
 251          }
 252  
 253          return $this->horizontal;
 254      }
 255  
 256      /**
 257       * Set Horizontal.
 258       *
 259       * @param string $horizontalAlignment see self::HORIZONTAL_*
 260       *
 261       * @return $this
 262       */
 263      public function setHorizontal(string $horizontalAlignment)
 264      {
 265          $horizontalAlignment = strtolower($horizontalAlignment);
 266          if ($horizontalAlignment === self::HORIZONTAL_CENTER_CONTINUOUS_LC) {
 267              $horizontalAlignment = self::HORIZONTAL_CENTER_CONTINUOUS;
 268          }
 269  
 270          if ($this->isSupervisor) {
 271              $styleArray = $this->getStyleArray(['horizontal' => $horizontalAlignment]);
 272              $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
 273          } else {
 274              $this->horizontal = $horizontalAlignment;
 275          }
 276  
 277          return $this;
 278      }
 279  
 280      /**
 281       * Get Vertical.
 282       *
 283       * @return null|string
 284       */
 285      public function getVertical()
 286      {
 287          if ($this->isSupervisor) {
 288              return $this->getSharedComponent()->getVertical();
 289          }
 290  
 291          return $this->vertical;
 292      }
 293  
 294      /**
 295       * Set Vertical.
 296       *
 297       * @param string $verticalAlignment see self::VERTICAL_*
 298       *
 299       * @return $this
 300       */
 301      public function setVertical($verticalAlignment)
 302      {
 303          $verticalAlignment = strtolower($verticalAlignment);
 304  
 305          if ($this->isSupervisor) {
 306              $styleArray = $this->getStyleArray(['vertical' => $verticalAlignment]);
 307              $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
 308          } else {
 309              $this->vertical = $verticalAlignment;
 310          }
 311  
 312          return $this;
 313      }
 314  
 315      /**
 316       * Get TextRotation.
 317       *
 318       * @return null|int
 319       */
 320      public function getTextRotation()
 321      {
 322          if ($this->isSupervisor) {
 323              return $this->getSharedComponent()->getTextRotation();
 324          }
 325  
 326          return $this->textRotation;
 327      }
 328  
 329      /**
 330       * Set TextRotation.
 331       *
 332       * @param int $angleInDegrees
 333       *
 334       * @return $this
 335       */
 336      public function setTextRotation($angleInDegrees)
 337      {
 338          // Excel2007 value 255 => PhpSpreadsheet value -165
 339          if ($angleInDegrees == self::TEXTROTATION_STACK_EXCEL) {
 340              $angleInDegrees = self::TEXTROTATION_STACK_PHPSPREADSHEET;
 341          }
 342  
 343          // Set rotation
 344          if (($angleInDegrees >= -90 && $angleInDegrees <= 90) || $angleInDegrees == self::TEXTROTATION_STACK_PHPSPREADSHEET) {
 345              if ($this->isSupervisor) {
 346                  $styleArray = $this->getStyleArray(['textRotation' => $angleInDegrees]);
 347                  $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
 348              } else {
 349                  $this->textRotation = $angleInDegrees;
 350              }
 351          } else {
 352              throw new PhpSpreadsheetException('Text rotation should be a value between -90 and 90.');
 353          }
 354  
 355          return $this;
 356      }
 357  
 358      /**
 359       * Get Wrap Text.
 360       *
 361       * @return bool
 362       */
 363      public function getWrapText()
 364      {
 365          if ($this->isSupervisor) {
 366              return $this->getSharedComponent()->getWrapText();
 367          }
 368  
 369          return $this->wrapText;
 370      }
 371  
 372      /**
 373       * Set Wrap Text.
 374       *
 375       * @param bool $wrapped
 376       *
 377       * @return $this
 378       */
 379      public function setWrapText($wrapped)
 380      {
 381          if ($wrapped == '') {
 382              $wrapped = false;
 383          }
 384          if ($this->isSupervisor) {
 385              $styleArray = $this->getStyleArray(['wrapText' => $wrapped]);
 386              $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
 387          } else {
 388              $this->wrapText = $wrapped;
 389          }
 390  
 391          return $this;
 392      }
 393  
 394      /**
 395       * Get Shrink to fit.
 396       *
 397       * @return bool
 398       */
 399      public function getShrinkToFit()
 400      {
 401          if ($this->isSupervisor) {
 402              return $this->getSharedComponent()->getShrinkToFit();
 403          }
 404  
 405          return $this->shrinkToFit;
 406      }
 407  
 408      /**
 409       * Set Shrink to fit.
 410       *
 411       * @param bool $shrink
 412       *
 413       * @return $this
 414       */
 415      public function setShrinkToFit($shrink)
 416      {
 417          if ($shrink == '') {
 418              $shrink = false;
 419          }
 420          if ($this->isSupervisor) {
 421              $styleArray = $this->getStyleArray(['shrinkToFit' => $shrink]);
 422              $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
 423          } else {
 424              $this->shrinkToFit = $shrink;
 425          }
 426  
 427          return $this;
 428      }
 429  
 430      /**
 431       * Get indent.
 432       *
 433       * @return int
 434       */
 435      public function getIndent()
 436      {
 437          if ($this->isSupervisor) {
 438              return $this->getSharedComponent()->getIndent();
 439          }
 440  
 441          return $this->indent;
 442      }
 443  
 444      /**
 445       * Set indent.
 446       *
 447       * @param int $indent
 448       *
 449       * @return $this
 450       */
 451      public function setIndent($indent)
 452      {
 453          if ($indent > 0) {
 454              if (
 455                  $this->getHorizontal() != self::HORIZONTAL_GENERAL &&
 456                  $this->getHorizontal() != self::HORIZONTAL_LEFT &&
 457                  $this->getHorizontal() != self::HORIZONTAL_RIGHT &&
 458                  $this->getHorizontal() != self::HORIZONTAL_DISTRIBUTED
 459              ) {
 460                  $indent = 0; // indent not supported
 461              }
 462          }
 463          if ($this->isSupervisor) {
 464              $styleArray = $this->getStyleArray(['indent' => $indent]);
 465              $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
 466          } else {
 467              $this->indent = $indent;
 468          }
 469  
 470          return $this;
 471      }
 472  
 473      /**
 474       * Get read order.
 475       *
 476       * @return int
 477       */
 478      public function getReadOrder()
 479      {
 480          if ($this->isSupervisor) {
 481              return $this->getSharedComponent()->getReadOrder();
 482          }
 483  
 484          return $this->readOrder;
 485      }
 486  
 487      /**
 488       * Set read order.
 489       *
 490       * @param int $readOrder
 491       *
 492       * @return $this
 493       */
 494      public function setReadOrder($readOrder)
 495      {
 496          if ($readOrder < 0 || $readOrder > 2) {
 497              $readOrder = 0;
 498          }
 499          if ($this->isSupervisor) {
 500              $styleArray = $this->getStyleArray(['readOrder' => $readOrder]);
 501              $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
 502          } else {
 503              $this->readOrder = $readOrder;
 504          }
 505  
 506          return $this;
 507      }
 508  
 509      /**
 510       * Get hash code.
 511       *
 512       * @return string Hash code
 513       */
 514      public function getHashCode()
 515      {
 516          if ($this->isSupervisor) {
 517              return $this->getSharedComponent()->getHashCode();
 518          }
 519  
 520          return md5(
 521              $this->horizontal .
 522              $this->vertical .
 523              $this->textRotation .
 524              ($this->wrapText ? 't' : 'f') .
 525              ($this->shrinkToFit ? 't' : 'f') .
 526              $this->indent .
 527              $this->readOrder .
 528              __CLASS__
 529          );
 530      }
 531  
 532      protected function exportArray1(): array
 533      {
 534          $exportedArray = [];
 535          $this->exportArray2($exportedArray, 'horizontal', $this->getHorizontal());
 536          $this->exportArray2($exportedArray, 'indent', $this->getIndent());
 537          $this->exportArray2($exportedArray, 'readOrder', $this->getReadOrder());
 538          $this->exportArray2($exportedArray, 'shrinkToFit', $this->getShrinkToFit());
 539          $this->exportArray2($exportedArray, 'textRotation', $this->getTextRotation());
 540          $this->exportArray2($exportedArray, 'vertical', $this->getVertical());
 541          $this->exportArray2($exportedArray, 'wrapText', $this->getWrapText());
 542  
 543          return $exportedArray;
 544      }
 545  }