From 9467b5a8100583963590ec5afca39a2ff3dfa859 Mon Sep 17 00:00:00 2001 From: Adrien Loison Date: Fri, 21 Aug 2015 20:48:57 -0700 Subject: [PATCH] Add support for font color --- README.md | 3 + .../Exception/InvalidColorException.php | 12 +++ src/Spout/Writer/Style/Color.php | 76 +++++++++++++++ src/Spout/Writer/Style/Style.php | 31 +++++++ src/Spout/Writer/Style/StyleBuilder.php | 12 +++ src/Spout/Writer/XLSX/Helper/StyleHelper.php | 7 +- tests/Spout/Writer/Style/ColorTest.php | 93 +++++++++++++++++++ .../Spout/Writer/XLSX/WriterWithStyleTest.php | 12 ++- 8 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 src/Spout/Writer/Exception/InvalidColorException.php create mode 100644 src/Spout/Writer/Style/Color.php create mode 100644 tests/Spout/Writer/Style/ColorTest.php diff --git a/README.md b/README.md index d1b632c..d137e01 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ use Box\Spout\Writer\Style\StyleBuilder; $style = (new StyleBuilder()) ->setFontBold() ->setFontSize(15) + ->setFontColor(Color::BLUE) ->setShouldWrapText() ->build(); @@ -180,6 +181,8 @@ Font | Bold | `StyleBuilder::setFontBold()` | Strikethrough | `StyleBuilder::setFontStrikethrough()` | Font name | `StyleBuilder::setFontName('Arial')` | Font size | `StyleBuilder::setFontSize(14)` + | Font color | `StyleBuilder::setFontSize(Color::BLUE)` + | | `StyleBuilder::setFontSize(Color::rgb(0, 128, 255))` Alignment | Wrap text | `StyleBuilder::setShouldWrapText()` diff --git a/src/Spout/Writer/Exception/InvalidColorException.php b/src/Spout/Writer/Exception/InvalidColorException.php new file mode 100644 index 0000000..b00dfa4 --- /dev/null +++ b/src/Spout/Writer/Exception/InvalidColorException.php @@ -0,0 +1,12 @@ + 255) { + throw new InvalidColorException("The RGB components must be between 0 and 255. Received: $colorComponent"); + } + } + + /** + * Converts the color component to its corresponding hexadecimal value + * + * @param int $colorComponent Color component, 0 - 255 + * @return string Corresponding hexadecimal value, with a leading 0 if needed. E.g "0f", "2d" + */ + protected static function convertColorComponentToHex($colorComponent) + { + return str_pad(dechex($colorComponent), 2, '0', 0); + } +} diff --git a/src/Spout/Writer/Style/Style.php b/src/Spout/Writer/Style/Style.php index e778854..7b95769 100644 --- a/src/Spout/Writer/Style/Style.php +++ b/src/Spout/Writer/Style/Style.php @@ -12,6 +12,7 @@ class Style { /** Default font values */ const DEFAULT_FONT_SIZE = 11; + const DEFAULT_FONT_COLOR = Color::BLACK; const DEFAULT_FONT_NAME = 'Arial'; /** @var int|null Style ID */ @@ -42,6 +43,11 @@ class Style /** @var bool Whether the font size property was set */ protected $hasSetFontSize = false; + /** @var string Font color */ + protected $fontColor = self::DEFAULT_FONT_COLOR; + /** @var bool Whether the font color property was set */ + protected $hasSetFontColor = false; + /** @var string Font name */ protected $fontName = self::DEFAULT_FONT_NAME; /** @var bool Whether the font name property was set */ @@ -169,6 +175,28 @@ class Style return $this; } + /** + * @return string + */ + public function getFontColor() + { + return $this->fontColor; + } + + /** + * Sets the font color. + * + * @param string $fontColor ARGB color (@see Color) + * @return Style + */ + public function setFontColor($fontColor) + { + $this->fontColor = $fontColor; + $this->hasSetFontColor = true; + $this->shouldApplyFont = true; + return $this; + } + /** * @return string */ @@ -265,6 +293,9 @@ class Style if (!$this->hasSetFontSize && $baseStyle->getFontSize() !== self::DEFAULT_FONT_SIZE) { $mergedStyle->setFontSize($baseStyle->getFontSize()); } + if (!$this->hasSetFontSize && $baseStyle->getFontColor() !== self::DEFAULT_FONT_COLOR) { + $mergedStyle->setFontColor($baseStyle->getFontColor()); + } if (!$this->hasSetFontName && $baseStyle->getFontName() !== self::DEFAULT_FONT_NAME) { $mergedStyle->setFontName($baseStyle->getFontName()); } diff --git a/src/Spout/Writer/Style/StyleBuilder.php b/src/Spout/Writer/Style/StyleBuilder.php index 6725f2a..8629ca6 100644 --- a/src/Spout/Writer/Style/StyleBuilder.php +++ b/src/Spout/Writer/Style/StyleBuilder.php @@ -77,6 +77,18 @@ class StyleBuilder return $this; } + /** + * Sets the font color. + * + * @param string $fontColor ARGB color (@see Color) + * @return StyleBuilder + */ + public function setFontColor($fontColor) + { + $this->style->setFontColor($fontColor); + return $this; + } + /** * Sets the font name. * diff --git a/src/Spout/Writer/XLSX/Helper/StyleHelper.php b/src/Spout/Writer/XLSX/Helper/StyleHelper.php index 8bae6af..077b9af 100644 --- a/src/Spout/Writer/XLSX/Helper/StyleHelper.php +++ b/src/Spout/Writer/XLSX/Helper/StyleHelper.php @@ -150,9 +150,14 @@ EOD; { $content = ' ' . PHP_EOL; + /** @var \Box\Spout\Writer\Style\Style $style */ foreach ($this->styleIdToStyleMappingTable as $style) { $content .= ' ' . PHP_EOL; + $content .= ' ' . PHP_EOL; + $content .= ' ' . PHP_EOL; + $content .= ' ' . PHP_EOL; + if ($style->isFontBold()) { $content .= ' ' . PHP_EOL; } @@ -166,8 +171,6 @@ EOD; $content .= ' ' . PHP_EOL; } - $content .= ' ' . PHP_EOL; - $content .= ' ' . PHP_EOL; $content .= ' ' . PHP_EOL; } diff --git a/tests/Spout/Writer/Style/ColorTest.php b/tests/Spout/Writer/Style/ColorTest.php new file mode 100644 index 0000000..6824d8d --- /dev/null +++ b/tests/Spout/Writer/Style/ColorTest.php @@ -0,0 +1,93 @@ +assertEquals($expectedColor, $color); + } + + /** + * @return array + */ + public function dataProviderForTestRGBAInvalidColorComponents() + { + return [ + [-1, 0, 0], + [0, -1, 0], + [0, 0, -1], + [999, 0, 0], + [0, 999, 0], + [0, 0, 999], + [null, 0, 0], + [0, null, 0], + [0, 0, null], + ['1', 0, 0], + [0, '1', 0], + [0, 0, '1'], + [true, 0, 0], + [0, true, 0], + [0, 0, true], + ]; + } + + /** + * @dataProvider dataProviderForTestRGBAInvalidColorComponents + * @expectedException \Box\Spout\Writer\Exception\InvalidColorException + * + * @param int $red + * @param int $green + * @param int $blue + * @return void + */ + public function testRGBInvalidColorComponents($red, $green, $blue) + { + Color::rgb($red, $green, $blue); + } +} diff --git a/tests/Spout/Writer/XLSX/WriterWithStyleTest.php b/tests/Spout/Writer/XLSX/WriterWithStyleTest.php index 9172d1c..89d0374 100644 --- a/tests/Spout/Writer/XLSX/WriterWithStyleTest.php +++ b/tests/Spout/Writer/XLSX/WriterWithStyleTest.php @@ -4,6 +4,8 @@ namespace Box\Spout\Writer\XLSX; use Box\Spout\Common\Type; use Box\Spout\TestUsingResource; +use Box\Spout\Writer\Style\Color; +use Box\Spout\Writer\Style\Style; use Box\Spout\Writer\Style\StyleBuilder; use Box\Spout\Writer\WriterFactory; @@ -110,6 +112,7 @@ class WriterWithStyleTest extends \PHPUnit_Framework_TestCase ->build(); $style2 = (new StyleBuilder()) ->setFontSize(15) + ->setFontColor(Color::RED) ->setFontName('Arial') ->build(); @@ -123,24 +126,27 @@ class WriterWithStyleTest extends \PHPUnit_Framework_TestCase // First font should be the default one $defaultFontElement = $fontElements->item(0); - $this->assertChildrenNumEquals(2, $defaultFontElement, 'The default font should only have 2 properties.'); + $this->assertChildrenNumEquals(3, $defaultFontElement, 'The default font should only have 3 properties.'); $this->assertFirstChildHasAttributeEquals((string) Writer::DEFAULT_FONT_SIZE, $defaultFontElement, 'sz', 'val'); + $this->assertFirstChildHasAttributeEquals(Style::DEFAULT_FONT_COLOR, $defaultFontElement, 'color', 'rgb'); $this->assertFirstChildHasAttributeEquals(Writer::DEFAULT_FONT_NAME, $defaultFontElement, 'name', 'val'); // Second font should contain data from the first created style $secondFontElement = $fontElements->item(1); - $this->assertChildrenNumEquals(6, $secondFontElement, 'The font should only have 6 properties (4 custom styles + 2 default styles).'); + $this->assertChildrenNumEquals(7, $secondFontElement, 'The font should only have 7 properties (4 custom styles + 3 default styles).'); $this->assertChildExists($secondFontElement, 'b'); $this->assertChildExists($secondFontElement, 'i'); $this->assertChildExists($secondFontElement, 'u'); $this->assertChildExists($secondFontElement, 'strike'); $this->assertFirstChildHasAttributeEquals((string) Writer::DEFAULT_FONT_SIZE, $secondFontElement, 'sz', 'val'); + $this->assertFirstChildHasAttributeEquals(Style::DEFAULT_FONT_COLOR, $secondFontElement, 'color', 'rgb'); $this->assertFirstChildHasAttributeEquals(Writer::DEFAULT_FONT_NAME, $secondFontElement, 'name', 'val'); // Third font should contain data from the second created style $thirdFontElement = $fontElements->item(2); - $this->assertChildrenNumEquals(2, $thirdFontElement, 'The font should only have 2 properties.'); + $this->assertChildrenNumEquals(3, $thirdFontElement, 'The font should only have 3 properties.'); $this->assertFirstChildHasAttributeEquals('15', $thirdFontElement, 'sz', 'val'); + $this->assertFirstChildHasAttributeEquals(Color::RED, $thirdFontElement, 'color', 'rgb'); $this->assertFirstChildHasAttributeEquals('Arial', $thirdFontElement, 'name', 'val'); }