diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 280e3fe1a1..bf696a608e 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -539,16 +539,14 @@ public function load(string $filename, int $flags = 0): Spreadsheet if ($xpath === null) { $xmlStyles = self::testSimpleXml(null); } else { - // I think Nonamespace is okay because I'm using xpath. - $xmlStyles = $this->loadZipNonamespace("$dir/$xpath[Target]", $mainNS); + $xmlStyles = $this->loadZip("$dir/$xpath[Target]", $mainNS); } - $xmlStyles->registerXPathNamespace('smm', Namespaces::MAIN); - $fills = self::xpathNoFalse($xmlStyles, 'smm:fills/smm:fill'); - $fonts = self::xpathNoFalse($xmlStyles, 'smm:fonts/smm:font'); - $borders = self::xpathNoFalse($xmlStyles, 'smm:borders/smm:border'); - $xfTags = self::xpathNoFalse($xmlStyles, 'smm:cellXfs/smm:xf'); - $cellXfTags = self::xpathNoFalse($xmlStyles, 'smm:cellStyleXfs/smm:xf'); + $fills = self::extractStyles($xmlStyles, 'fills', 'fill'); + $fonts = self::extractStyles($xmlStyles, 'fonts', 'font'); + $borders = self::extractStyles($xmlStyles, 'borders', 'border'); + $xfTags = self::extractStyles($xmlStyles, 'cellXfs', 'xf'); + $cellXfTags = self::extractStyles($xmlStyles, 'cellStyleXfs', 'xf'); $styles = []; $cellStyles = []; @@ -559,6 +557,7 @@ public function load(string $filename, int $flags = 0): Spreadsheet if (isset($numFmts) && ($numFmts !== null)) { $numFmts->registerXPathNamespace('sml', $mainNS); } + $this->styleReader->setNamespace($mainNS); if (!$this->readDataOnly/* && $xmlStyles*/) { foreach ($xfTags as $xfTag) { $xf = self::getAttributes($xfTag); @@ -643,6 +642,7 @@ public function load(string $filename, int $flags = 0): Spreadsheet } } $this->styleReader->setStyleXml($xmlStyles); + $this->styleReader->setNamespace($mainNS); $this->styleReader->setStyleBaseData($theme, $styles, $cellStyles); $dxfs = $this->styleReader->dxfs($this->readDataOnly); $styles = $this->styleReader->styles(); @@ -2088,4 +2088,16 @@ private function readAutoFilterTablesInTablesFile( } } } + + private static function extractStyles(?SimpleXMLElement $sxml, string $node1, string $node2): array + { + $array = []; + if ($sxml && $sxml->{$node1}->{$node2}) { + foreach ($sxml->{$node1}->{$node2} as $node) { + $array[] = $node; + } + } + + return $array; + } } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Styles.php b/src/PhpSpreadsheet/Reader/Xlsx/Styles.php index 6f01c7457d..65dac529f3 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Styles.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Styles.php @@ -33,6 +33,37 @@ class Styles extends BaseParserClass /** @var SimpleXMLElement */ private $styleXml; + /** @var string */ + private $namespace = ''; + + public function setNamespace(string $namespace): void + { + $this->namespace = $namespace; + } + + /** + * Cast SimpleXMLElement to bool to overcome Scrutinizer problem. + * + * @param mixed $value + */ + private static function castBool($value): bool + { + return (bool) $value; + } + + private function getStyleAttributes(SimpleXMLElement $value): SimpleXMLElement + { + $attr = null; + if (self::castBool($value)) { + $attr = $value->attributes(''); + if ($attr === null || count($attr) === 0) { + $attr = $value->attributes($this->namespace); + } + } + + return Xlsx::testSimpleXml($attr); + } + public function setStyleXml(SimpleXmlElement $styleXml): void { $this->styleXml = $styleXml; @@ -52,48 +83,62 @@ public function setStyleBaseData(?Theme $theme = null, array $styles = [], array public function readFontStyle(Font $fontStyle, SimpleXMLElement $fontStyleXml): void { - if (isset($fontStyleXml->name, $fontStyleXml->name['val'])) { - $fontStyle->setName((string) $fontStyleXml->name['val']); + if (isset($fontStyleXml->name)) { + $attr = $this->getStyleAttributes($fontStyleXml->name); + if (isset($attr['val'])) { + $fontStyle->setName((string) $attr['val']); + } } - if (isset($fontStyleXml->sz, $fontStyleXml->sz['val'])) { - $fontStyle->setSize((float) $fontStyleXml->sz['val']); + if (isset($fontStyleXml->sz)) { + $attr = $this->getStyleAttributes($fontStyleXml->sz); + if (isset($attr['val'])) { + $fontStyle->setSize((float) $attr['val']); + } } if (isset($fontStyleXml->b)) { - $fontStyle->setBold(!isset($fontStyleXml->b['val']) || self::boolean((string) $fontStyleXml->b['val'])); + $attr = $this->getStyleAttributes($fontStyleXml->b); + $fontStyle->setBold(!isset($attr['val']) || self::boolean((string) $attr['val'])); } if (isset($fontStyleXml->i)) { - $fontStyle->setItalic(!isset($fontStyleXml->i['val']) || self::boolean((string) $fontStyleXml->i['val'])); + $attr = $this->getStyleAttributes($fontStyleXml->i); + $fontStyle->setItalic(!isset($attr['val']) || self::boolean((string) $attr['val'])); } if (isset($fontStyleXml->strike)) { - $fontStyle->setStrikethrough( - !isset($fontStyleXml->strike['val']) || self::boolean((string) $fontStyleXml->strike['val']) - ); + $attr = $this->getStyleAttributes($fontStyleXml->strike); + $fontStyle->setStrikethrough(!isset($attr['val']) || self::boolean((string) $attr['val'])); } $fontStyle->getColor()->setARGB($this->readColor($fontStyleXml->color)); - if (isset($fontStyleXml->u) && !isset($fontStyleXml->u['val'])) { - $fontStyle->setUnderline(Font::UNDERLINE_SINGLE); - } elseif (isset($fontStyleXml->u, $fontStyleXml->u['val'])) { - $fontStyle->setUnderline((string) $fontStyleXml->u['val']); + if (isset($fontStyleXml->u)) { + $attr = $this->getStyleAttributes($fontStyleXml->u); + if (!isset($attr['val'])) { + $fontStyle->setUnderline(Font::UNDERLINE_SINGLE); + } else { + $fontStyle->setUnderline((string) $attr['val']); + } } - - if (isset($fontStyleXml->vertAlign, $fontStyleXml->vertAlign['val'])) { - $verticalAlign = strtolower((string) $fontStyleXml->vertAlign['val']); - if ($verticalAlign === 'superscript') { - $fontStyle->setSuperscript(true); - } elseif ($verticalAlign === 'subscript') { - $fontStyle->setSubscript(true); + if (isset($fontStyleXml->vertAlign)) { + $attr = $this->getStyleAttributes($fontStyleXml->vertAlign); + if (!isset($attr['val'])) { + $verticalAlign = strtolower((string) $attr['val']); + if ($verticalAlign === 'superscript') { + $fontStyle->setSuperscript(true); + } elseif ($verticalAlign === 'subscript') { + $fontStyle->setSubscript(true); + } } } } private function readNumberFormat(NumberFormat $numfmtStyle, SimpleXMLElement $numfmtStyleXml): void { - if ($numfmtStyleXml->count() === 0) { + if ((string) $numfmtStyleXml['formatCode'] !== '') { + $numfmtStyle->setFormatCode(self::formatGeneral((string) $numfmtStyleXml['formatCode'])); + return; } - $numfmt = Xlsx::getAttributes($numfmtStyleXml); - if ($numfmt->count() > 0 && isset($numfmt['formatCode'])) { + $numfmt = $this->getStyleAttributes($numfmtStyleXml); + if (isset($numfmt['formatCode'])) { $numfmtStyle->setFormatCode(self::formatGeneral((string) $numfmt['formatCode'])); } } @@ -103,10 +148,11 @@ public function readFillStyle(Fill $fillStyle, SimpleXMLElement $fillStyleXml): if ($fillStyleXml->gradientFill) { /** @var SimpleXMLElement $gradientFill */ $gradientFill = $fillStyleXml->gradientFill[0]; - if (!empty($gradientFill['type'])) { - $fillStyle->setFillType((string) $gradientFill['type']); + $attr = $this->getStyleAttributes($gradientFill); + if (!empty($attr['type'])) { + $fillStyle->setFillType((string) $attr['type']); } - $fillStyle->setRotation((float) ($gradientFill['degree'])); + $fillStyle->setRotation((float) ($attr['degree'])); $gradientFill->registerXPathNamespace('sml', Namespaces::MAIN); $fillStyle->getStartColor()->setARGB($this->readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color)); $fillStyle->getEndColor()->setARGB($this->readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color)); @@ -121,9 +167,14 @@ public function readFillStyle(Fill $fillStyle, SimpleXMLElement $fillStyleXml): $defaultFillStyle = Fill::FILL_SOLID; } - $patternType = (string) $fillStyleXml->patternFill['patternType'] != '' - ? (string) $fillStyleXml->patternFill['patternType'] - : $defaultFillStyle; + $type = ''; + if ((string) $fillStyleXml->patternFill['patternType'] !== '') { + $type = (string) $fillStyleXml->patternFill['patternType']; + } else { + $attr = $this->getStyleAttributes($fillStyleXml->patternFill); + $type = (string) $attr['patternType']; + } + $patternType = ($type === '') ? $defaultFillStyle : $type; $fillStyle->setFillType($patternType); } @@ -131,8 +182,10 @@ public function readFillStyle(Fill $fillStyle, SimpleXMLElement $fillStyleXml): public function readBorderStyle(Borders $borderStyle, SimpleXMLElement $borderStyleXml): void { - $diagonalUp = self::boolean((string) $borderStyleXml['diagonalUp']); - $diagonalDown = self::boolean((string) $borderStyleXml['diagonalDown']); + $diagonalUp = $this->getAttribute($borderStyleXml, 'diagonalUp'); + $diagonalUp = self::boolean($diagonalUp); + $diagonalDown = $this->getAttribute($borderStyleXml, 'diagonalDown'); + $diagonalDown = self::boolean($diagonalDown); if (!$diagonalUp && !$diagonalDown) { $borderStyle->setDiagonalDirection(Borders::DIAGONAL_NONE); } elseif ($diagonalUp && !$diagonalDown) { @@ -150,10 +203,26 @@ public function readBorderStyle(Borders $borderStyle, SimpleXMLElement $borderSt $this->readBorder($borderStyle->getDiagonal(), $borderStyleXml->diagonal); } + private function getAttribute(SimpleXMLElement $xml, string $attribute): string + { + $style = ''; + if ((string) $xml[$attribute] !== '') { + $style = (string) $xml[$attribute]; + } else { + $attr = $this->getStyleAttributes($xml); + if (isset($attr[$attribute])) { + $style = (string) $attr[$attribute]; + } + } + + return $style; + } + private function readBorder(Border $border, SimpleXMLElement $borderXml): void { - if (isset($borderXml['style'])) { - $border->setBorderStyle((string) $borderXml['style']); + $style = $this->getAttribute($borderXml, 'style'); + if ($style !== '') { + $border->setBorderStyle((string) $style); } if (isset($borderXml->color)) { $border->getColor()->setARGB($this->readColor($borderXml->color)); @@ -162,25 +231,25 @@ private function readBorder(Border $border, SimpleXMLElement $borderXml): void public function readAlignmentStyle(Alignment $alignment, SimpleXMLElement $alignmentXml): void { - $alignment->setHorizontal((string) $alignmentXml['horizontal']); - $alignment->setVertical((string) $alignmentXml['vertical']); - - $textRotation = 0; - if ((int) $alignmentXml['textRotation'] <= 90) { - $textRotation = (int) $alignmentXml['textRotation']; - } elseif ((int) $alignmentXml['textRotation'] > 90) { - $textRotation = 90 - (int) $alignmentXml['textRotation']; - } - - $alignment->setTextRotation((int) $textRotation); - $alignment->setWrapText(self::boolean((string) $alignmentXml['wrapText'])); - $alignment->setShrinkToFit(self::boolean((string) $alignmentXml['shrinkToFit'])); - $alignment->setIndent( - (int) ((string) $alignmentXml['indent']) > 0 ? (int) ((string) $alignmentXml['indent']) : 0 - ); - $alignment->setReadOrder( - (int) ((string) $alignmentXml['readingOrder']) > 0 ? (int) ((string) $alignmentXml['readingOrder']) : 0 - ); + $horizontal = $this->getAttribute($alignmentXml, 'horizontal'); + $alignment->setHorizontal($horizontal); + $vertical = $this->getAttribute($alignmentXml, 'vertical'); + $alignment->setVertical((string) $vertical); + + $textRotation = (int) $this->getAttribute($alignmentXml, 'textRotation'); + if ($textRotation > 90) { + $textRotation = 90 - $textRotation; + } + $alignment->setTextRotation($textRotation); + + $wrapText = $this->getAttribute($alignmentXml, 'wrapText'); + $alignment->setWrapText(self::boolean((string) $wrapText)); + $shrinkToFit = $this->getAttribute($alignmentXml, 'shrinkToFit'); + $alignment->setShrinkToFit(self::boolean((string) $shrinkToFit)); + $indent = (int) $this->getAttribute($alignmentXml, 'indent'); + $alignment->setIndent(max($indent, 0)); + $readingOrder = (int) $this->getAttribute($alignmentXml, 'readingOrder'); + $alignment->setReadOrder(max($readingOrder, 0)); } private static function formatGeneral(string $formatString): string @@ -223,8 +292,8 @@ public function readStyle(Style $docStyle, $style): void // protection if (isset($style->protection)) { - $this->readProtectionLocked($docStyle, $style); - $this->readProtectionHidden($docStyle, $style); + $this->readProtectionLocked($docStyle, $style->protection); + $this->readProtectionHidden($docStyle, $style->protection); } // top-level style settings @@ -235,13 +304,20 @@ public function readStyle(Style $docStyle, $style): void /** * Read protection locked attribute. - * - * @param SimpleXMLElement|stdClass $style */ - public function readProtectionLocked(Style $docStyle, $style): void + public function readProtectionLocked(Style $docStyle, SimpleXMLElement $style): void { - if (isset($style->protection['locked'])) { - if (self::boolean((string) $style->protection['locked'])) { + $locked = ''; + if ((string) $style['locked'] !== '') { + $locked = (string) $style['locked']; + } else { + $attr = $this->getStyleAttributes($style); + if (isset($attr['locked'])) { + $locked = (string) $attr['locked']; + } + } + if ($locked !== '') { + if (self::boolean($locked)) { $docStyle->getProtection()->setLocked(Protection::PROTECTION_PROTECTED); } else { $docStyle->getProtection()->setLocked(Protection::PROTECTION_UNPROTECTED); @@ -251,13 +327,20 @@ public function readProtectionLocked(Style $docStyle, $style): void /** * Read protection hidden attribute. - * - * @param SimpleXMLElement|stdClass $style */ - public function readProtectionHidden(Style $docStyle, $style): void + public function readProtectionHidden(Style $docStyle, SimpleXMLElement $style): void { - if (isset($style->protection['hidden'])) { - if (self::boolean((string) $style->protection['hidden'])) { + $hidden = ''; + if ((string) $style['hidden'] !== '') { + $hidden = (string) $style['hidden']; + } else { + $attr = $this->getStyleAttributes($style); + if (isset($attr['hidden'])) { + $hidden = (string) $attr['hidden']; + } + } + if ($hidden !== '') { + if (self::boolean((string) $hidden)) { $docStyle->getProtection()->setHidden(Protection::PROTECTION_PROTECTED); } else { $docStyle->getProtection()->setHidden(Protection::PROTECTION_UNPROTECTED); @@ -267,15 +350,18 @@ public function readProtectionHidden(Style $docStyle, $style): void public function readColor(SimpleXMLElement $color, bool $background = false): string { - if (isset($color['rgb'])) { - return (string) $color['rgb']; - } elseif (isset($color['indexed'])) { - return Color::indexedColor((int) ($color['indexed'] - 7), $background)->getARGB() ?? ''; - } elseif (isset($color['theme'])) { + $attr = $this->getStyleAttributes($color); + if (isset($attr['rgb'])) { + return (string) $attr['rgb']; + } + if (isset($attr['indexed'])) { + return Color::indexedColor((int) ($attr['indexed'] - 7), $background)->getARGB() ?? ''; + } + if (isset($attr['theme'])) { if ($this->theme !== null) { - $returnColour = $this->theme->getColourByIndex((int) $color['theme']); - if (isset($color['tint'])) { - $tintAdjust = (float) $color['tint']; + $returnColour = $this->theme->getColourByIndex((int) $attr['theme']); + if (isset($attr['tint'])) { + $tintAdjust = (float) $attr['tint']; $returnColour = Color::changeBrightness($returnColour ?? '', $tintAdjust); } diff --git a/src/PhpSpreadsheet/Style/Color.php b/src/PhpSpreadsheet/Style/Color.php index c2d4f74905..6fd91c64f1 100644 --- a/src/PhpSpreadsheet/Style/Color.php +++ b/src/PhpSpreadsheet/Style/Color.php @@ -26,10 +26,24 @@ class Color extends Supervisor const COLOR_DARKGREEN = 'FF008000'; const COLOR_YELLOW = 'FFFFFF00'; const COLOR_DARKYELLOW = 'FF808000'; + const COLOR_MAGENTA = 'FFFF00FF'; + const COLOR_CYAN = 'FF00FFFF'; + + const NAMED_COLOR_TRANSLATIONS = [ + 'Black' => self::COLOR_BLACK, + 'White' => self::COLOR_WHITE, + 'Red' => self::COLOR_RED, + 'Green' => self::COLOR_GREEN, + 'Blue' => self::COLOR_BLUE, + 'Yellow' => self::COLOR_YELLOW, + 'Magenta' => self::COLOR_MAGENTA, + 'Cyan' => self::COLOR_CYAN, + ]; const VALIDATE_ARGB_SIZE = 8; const VALIDATE_RGB_SIZE = 6; - const VALIDATE_COLOR_VALUE = '/^[A-F0-9]{%d}$/i'; + const VALIDATE_COLOR_6 = '/^[A-F0-9]{6}$/i'; + const VALIDATE_COLOR_8 = '/^[A-F0-9]{8}$/i'; /** * Indexed colors array. @@ -66,7 +80,7 @@ public function __construct($colorValue = self::COLOR_BLACK, $isSupervisor = fal // Initialise values if (!$isConditional) { - $this->argb = $this->validateColor($colorValue, self::VALIDATE_ARGB_SIZE) ? $colorValue : self::COLOR_BLACK; + $this->argb = $this->validateColor($colorValue) ?: self::COLOR_BLACK; } } @@ -135,10 +149,23 @@ public function applyFromArray(array $styleArray) return $this; } - private function validateColor(string $colorValue, int $size): bool + private function validateColor(?string $colorValue): string { - return in_array(ucfirst(strtolower($colorValue)), self::NAMED_COLORS) || - preg_match(sprintf(self::VALIDATE_COLOR_VALUE, $size), $colorValue); + if ($colorValue === null || $colorValue === '') { + return self::COLOR_BLACK; + } + $named = ucfirst(strtolower($colorValue)); + if (array_key_exists($named, self::NAMED_COLOR_TRANSLATIONS)) { + return self::NAMED_COLOR_TRANSLATIONS[$named]; + } + if (preg_match(self::VALIDATE_COLOR_8, $colorValue) === 1) { + return $colorValue; + } + if (preg_match(self::VALIDATE_COLOR_6, $colorValue) === 1) { + return 'FF' . $colorValue; + } + + return ''; } /** @@ -163,9 +190,8 @@ public function getARGB(): ?string public function setARGB(?string $colorValue = self::COLOR_BLACK) { $this->hasChanged = true; - if ($colorValue === '' || $colorValue === null) { - $colorValue = self::COLOR_BLACK; - } elseif (!$this->validateColor($colorValue, self::VALIDATE_ARGB_SIZE)) { + $colorValue = $this->validateColor($colorValue); + if ($colorValue === '') { return $this; } @@ -200,21 +226,7 @@ public function getRGB(): string */ public function setRGB(?string $colorValue = self::COLOR_BLACK) { - $this->hasChanged = true; - if ($colorValue === '' || $colorValue === null) { - $colorValue = '000000'; - } elseif (!$this->validateColor($colorValue, self::VALIDATE_RGB_SIZE)) { - return $this; - } - - if ($this->isSupervisor) { - $styleArray = $this->getStyleArray(['argb' => 'FF' . $colorValue]); - $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray); - } else { - $this->argb = 'FF' . $colorValue; - } - - return $this; + return $this->setARGB($colorValue); } /** diff --git a/tests/PhpSpreadsheetTests/CommentTest.php b/tests/PhpSpreadsheetTests/CommentTest.php index f21efdf05e..e58afad44b 100644 --- a/tests/PhpSpreadsheetTests/CommentTest.php +++ b/tests/PhpSpreadsheetTests/CommentTest.php @@ -65,7 +65,7 @@ public function testSetFillColor(): void { $comment = new Comment(); $comment->setFillColor(new Color('RED')); - self::assertEquals('RED', $comment->getFillColor()->getARGB()); + self::assertEquals(Color::COLOR_RED, $comment->getFillColor()->getARGB()); } public function testSetAlignment(): void diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2494Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2494Test.php new file mode 100644 index 0000000000..ff400264fe --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2494Test.php @@ -0,0 +1,21 @@ +load($filename); + $sheet = $spreadsheet->getActiveSheet(); + self::assertTrue($sheet->getCell('C3')->getStyle()->getFont()->getBold()); + self::assertSame('FFBFBFBF', $sheet->getCell('D8')->getStyle()->getFill()->getStartColor()->getArgb()); + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/NamespaceNonStdTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/NamespaceNonStdTest.php index 5002b5d709..7f55c939dc 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/NamespaceNonStdTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/NamespaceNonStdTest.php @@ -77,9 +77,9 @@ public function testLoadXlsx(): void $spreadsheet = $reader->load(self::$testbook); $sheet = $spreadsheet->getSheet(0); self::assertEquals('SylkTest', $sheet->getTitle()); - if (strpos(__FILE__, 'NonStd') !== false) { - self::markTestIncomplete('Not yet ready'); - } + //if (strpos(__FILE__, 'NonStd') !== false) { + // self::markTestIncomplete('Not yet ready'); + //} self::assertEquals('FFFF0000', $sheet->getCell('A1')->getStyle()->getFont()->getColor()->getARGB()); self::assertEquals(Fill::FILL_PATTERN_GRAY125, $sheet->getCell('A2')->getStyle()->getFill()->getFillType()); @@ -168,9 +168,9 @@ public function testLoadXlsxSheet2Styles(): void $spreadsheet = $reader->load(self::$testbook); $sheet = $spreadsheet->getSheet(1); self::assertEquals('Second', $sheet->getTitle()); - if (strpos(__FILE__, 'NonStd') !== false) { - self::markTestIncomplete('Not yet ready'); - } + //if (strpos(__FILE__, 'NonStd') !== false) { + // self::markTestIncomplete('Not yet ready'); + //} self::assertEquals('center', $sheet->getCell('A2')->getStyle()->getAlignment()->getHorizontal()); self::assertSame('inherit', $sheet->getCell('A2')->getStyle()->getProtection()->getLocked()); self::assertEquals('top', $sheet->getCell('A3')->getStyle()->getAlignment()->getVertical()); diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/RichTextTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/RichTextTest.php new file mode 100644 index 0000000000..8fb8baca6b --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/RichTextTest.php @@ -0,0 +1,53 @@ +getActiveSheet(); + $richText = new RichText(); + $part1 = $richText->createTextRun('Red'); + $font1 = $part1->getFont(); + if ($font1 !== null) { + $font1->setName('Courier New'); + $font1->getColor()->setArgb('FFFF0000'); + } + $part2 = $richText->createTextRun('Blue'); + $font2 = $part2->getFont(); + if ($font2 !== null) { + $font2->setName('Times New Roman'); + $font2->setItalic(true); + $font2->getColor()->setArgb('FF0000FF'); + } + $sheet->setCellValue('A1', $richText); + + $spreadsheet = $this->writeAndReload($spreadsheetOld, 'Xlsx'); + $spreadsheetOld->disconnectWorksheets(); + $rsheet = $spreadsheet->getActiveSheet(); + $value = $rsheet->getCell('A1')->getValue(); + if ($value instanceof RichText) { + $elements = $value->getRichTextElements(); + self::assertCount(2, $elements); + $font1a = $elements[0]->getFont(); + $font2a = $elements[1]->getFont(); + self::assertNotNull($font1a); + self::assertNotNull($font2a); + self::assertSame('Courier New', $font1a->getName()); + self::assertSame('FFFF0000', $font1a->getColor()->getArgb()); + self::assertFalse($font1a->getItalic()); + self::assertSame('Times New Roman', $font2a->getName()); + self::assertSame('FF0000FF', $font2a->getColor()->getArgb()); + self::assertTrue($font2a->getItalic()); + } else { + self::fail('Did not see expected RichText'); + } + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/PhpSpreadsheetTests/Style/ColorTest.php b/tests/PhpSpreadsheetTests/Style/ColorTest.php index 9d0da3a233..6575c85017 100644 --- a/tests/PhpSpreadsheetTests/Style/ColorTest.php +++ b/tests/PhpSpreadsheetTests/Style/ColorTest.php @@ -157,4 +157,31 @@ public function testDefaultColor(): void self::assertEquals(Color::COLOR_BLACK, $color->getARGB()); self::assertEquals('000000', $color->getRGB()); } + + public function testNamedColors(): void + { + $color = new Color(); + $color->setARGB('Blue'); + self::assertEquals(Color::COLOR_BLUE, $color->getARGB()); + $color->setARGB('black'); + self::assertEquals(Color::COLOR_BLACK, $color->getARGB()); + $color->setARGB('wHite'); + self::assertEquals(Color::COLOR_WHITE, $color->getARGB()); + $color->setRGB('reD'); + self::assertEquals(Color::COLOR_RED, $color->getARGB()); + $color->setRGB('GREEN'); + self::assertEquals(Color::COLOR_GREEN, $color->getARGB()); + $color->setRGB('magenta'); + self::assertEquals(Color::COLOR_MAGENTA, $color->getARGB()); + $color->setRGB('YeLlOw'); + self::assertEquals(Color::COLOR_YELLOW, $color->getARGB()); + $color->setRGB('CYAN'); + self::assertEquals(Color::COLOR_CYAN, $color->getARGB()); + $color->setRGB('123456ab'); + self::assertEquals('123456ab', $color->getARGB()); + self::assertEquals('3456ab', $color->getRGB()); + $color->setARGB('3456cd'); + self::assertEquals('FF3456cd', $color->getARGB()); + self::assertEquals('3456cd', $color->getRGB()); + } } diff --git a/tests/data/Reader/XLSX/issue.2494.xlsx b/tests/data/Reader/XLSX/issue.2494.xlsx new file mode 100644 index 0000000000..f9a856faa0 Binary files /dev/null and b/tests/data/Reader/XLSX/issue.2494.xlsx differ