diff --git a/.gitignore b/.gitignore index c055246..a4bddd5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /vendor /composer.lock /.php_cs.cache +/.phpunit.result.cache diff --git a/.travis.yml b/.travis.yml index ac931ed..365ee59 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,16 +5,16 @@ language: php matrix: include: - - php: 7.1 - env: WITH_CS=true - - php: 7.1 - env: WITH_PHPUNIT=true WITH_COVERAGE=true - php: 7.2 env: WITH_PHPUNIT=true - php: 7.3 env: WITH_PHPUNIT=true + - php: 7.3 + env: WITH_PHPUNIT=true WITH_COVERAGE=true - php: 7.4 env: WITH_PHPUNIT=true + - php: 8.0 + env: WITH_PHPUNIT=true cache: @@ -42,7 +42,7 @@ before_script: script: - | if [[ "$WITH_CS" == "true" ]]; then - vendor/bin/php-cs-fixer fix --config=.php_cs.dist --verbose --diff --dry-run + vendor/bin/php-cs-fixer fix --config=.php_cs.dist --verbose --diff --dry-run --diff-format=udiff fi - | if [[ "$WITH_PHPUNIT" == "true" ]]; then diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8fa35c5..5db0f6e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -68,7 +68,21 @@ This will add your changes on top of what's already in upstream, minimizing merg Make sure that all tests are passing before submitting a pull request. -### Step 8: Send the pull request +### Step 8: Fix code style + +Run the following command to check the code style of your changes: + +``` +vendor/bin/php-cs-fixer fix --config=.php_cs.dist --verbose --diff --dry-run --diff-format=udiff +``` + +This will print a diff of proposed code style changes. To apply these suggestions, run the following command: + +``` +vendor/bin/php-cs-fixer fix --config=.php_cs.dist +``` + +### Step 9: Send the pull request Send the pull request from your feature branch to us. Be sure to include a description that lets us know what work you did. diff --git a/README.md b/README.md index 517f5a4..a9a0a9c 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Full documentation can be found at [https://opensource.box.com/spout/](https://o ## Requirements -* PHP version 7.1 or higher +* PHP version 7.2 or higher * PHP extension `php_zip` enabled * PHP extension `php_xmlreader` enabled diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 3952443..9b2e370 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -11,7 +11,7 @@ With the 3.0 version, this is now possible: each cell can have its own style. Spout 3.0 tries to enforce better typing. For instance, instead of using/returning generic arrays, Spout now makes use of specific `Row` and `Cell` objects that can encapsulate more data such as type, style, value. -Finally, **_Spout 3.0 only supports PHP 7.1 and above_**, as other PHP versions are no longer supported by the community. +Finally, **_Spout 3.2 only supports PHP 7.2 and above_**, as other PHP versions are no longer supported by the community. Reader changes -------------- diff --git a/composer.json b/composer.json index 8943469..4d9642b 100644 --- a/composer.json +++ b/composer.json @@ -12,12 +12,12 @@ } ], "require": { - "php": ">=7.1.0", + "php": ">=7.2.0", "ext-zip": "*", "ext-xmlreader" : "*" }, "require-dev": { - "phpunit/phpunit": "^7", + "phpunit/phpunit": "^8", "friendsofphp/php-cs-fixer": "^2" }, "suggest": { @@ -36,7 +36,7 @@ }, "config": { "platform": { - "php": "7.1" + "php": "7.2" } } } diff --git a/docs/_pages/getting-started.md b/docs/_pages/getting-started.md index 0004d4d..0e0b336 100755 --- a/docs/_pages/getting-started.md +++ b/docs/_pages/getting-started.md @@ -10,7 +10,7 @@ This guide will help you install {{ site.spout_html }} and teach you how to use ## Requirements -* PHP version 7.1 or higher +* PHP version 7.2 or higher * PHP extension `ext-zip` enabled * PHP extension `ext-xmlreader` enabled diff --git a/docs/_pages/guides/4-symfony-stream-content-large-spreadsheet.md b/docs/_pages/guides/4-symfony-stream-content-large-spreadsheet.md index fb203ae..165a4b3 100644 --- a/docs/_pages/guides/4-symfony-stream-content-large-spreadsheet.md +++ b/docs/_pages/guides/4-symfony-stream-content-large-spreadsheet.md @@ -94,7 +94,7 @@ class MyStreamController extends Controller $i++; // Flushing the buffer every N rows to stream echo'ed content. - if ($i % FLUSH_THRESHOLD === 0) { + if ($i % self::FLUSH_THRESHOLD === 0) { flush(); } } diff --git a/phpunit.xml b/phpunit.xml index 4c56189..4e410e2 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,6 +1,6 @@ shouldApplyBorder = true; $this->border = $border; + $this->isEmpty = false; return $this; } @@ -147,6 +154,7 @@ class Style $this->fontBold = true; $this->hasSetFontBold = true; $this->shouldApplyFont = true; + $this->isEmpty = false; return $this; } @@ -175,6 +183,7 @@ class Style $this->fontItalic = true; $this->hasSetFontItalic = true; $this->shouldApplyFont = true; + $this->isEmpty = false; return $this; } @@ -203,6 +212,7 @@ class Style $this->fontUnderline = true; $this->hasSetFontUnderline = true; $this->shouldApplyFont = true; + $this->isEmpty = false; return $this; } @@ -231,6 +241,7 @@ class Style $this->fontStrikethrough = true; $this->hasSetFontStrikethrough = true; $this->shouldApplyFont = true; + $this->isEmpty = false; return $this; } @@ -260,6 +271,7 @@ class Style $this->fontSize = $fontSize; $this->hasSetFontSize = true; $this->shouldApplyFont = true; + $this->isEmpty = false; return $this; } @@ -291,6 +303,7 @@ class Style $this->fontColor = $fontColor; $this->hasSetFontColor = true; $this->shouldApplyFont = true; + $this->isEmpty = false; return $this; } @@ -320,6 +333,7 @@ class Style $this->fontName = $fontName; $this->hasSetFontName = true; $this->shouldApplyFont = true; + $this->isEmpty = false; return $this; } @@ -350,6 +364,7 @@ class Style $this->cellAlignment = $cellAlignment; $this->hasSetCellAlignment = true; $this->shouldApplyCellAlignment = true; + $this->isEmpty = false; return $this; } @@ -386,6 +401,7 @@ class Style { $this->shouldWrapText = $shouldWrap; $this->hasSetWrapText = true; + $this->isEmpty = false; return $this; } @@ -415,6 +431,7 @@ class Style { $this->hasSetBackgroundColor = true; $this->backgroundColor = $color; + $this->isEmpty = false; return $this; } @@ -444,6 +461,7 @@ class Style { $this->hasSetFormat = true; $this->format = $format; + $this->isEmpty = false; return $this; } @@ -463,4 +481,29 @@ class Style { return $this->hasSetFormat; } + + /** + * @return bool + */ + public function isRegistered() : bool + { + return $this->isRegistered; + } + + public function markAsRegistered(?int $id) : void + { + $this->setId($id); + $this->isRegistered = true; + } + + public function unmarkAsRegistered() : void + { + $this->setId(0); + $this->isRegistered = false; + } + + public function isEmpty() : bool + { + return $this->isEmpty; + } } diff --git a/src/Spout/Writer/Common/Manager/RegisteredStyle.php b/src/Spout/Writer/Common/Manager/RegisteredStyle.php new file mode 100644 index 0000000..734c2b6 --- /dev/null +++ b/src/Spout/Writer/Common/Manager/RegisteredStyle.php @@ -0,0 +1,38 @@ +style = $style; + $this->isMatchingRowStyle = $isMatchingRowStyle; + } + + public function getStyle() : Style + { + return $this->style; + } + + public function isMatchingRowStyle() : bool + { + return $this->isMatchingRowStyle; + } +} diff --git a/src/Spout/Writer/Common/Manager/Style/PossiblyUpdatedStyle.php b/src/Spout/Writer/Common/Manager/Style/PossiblyUpdatedStyle.php new file mode 100644 index 0000000..6ccaa29 --- /dev/null +++ b/src/Spout/Writer/Common/Manager/Style/PossiblyUpdatedStyle.php @@ -0,0 +1,32 @@ +style = $style; + $this->isUpdated = $isUpdated; + } + + public function getStyle() : Style + { + return $this->style; + } + + public function isUpdated() : bool + { + return $this->isUpdated; + } +} diff --git a/src/Spout/Writer/Common/Manager/Style/StyleManager.php b/src/Spout/Writer/Common/Manager/Style/StyleManager.php index 77eec73..e2b5ebd 100644 --- a/src/Spout/Writer/Common/Manager/Style/StyleManager.php +++ b/src/Spout/Writer/Common/Manager/Style/StyleManager.php @@ -50,13 +50,11 @@ class StyleManager implements StyleManagerInterface * Typically, set "wrap text" if a cell contains a new line. * * @param Cell $cell - * @return Style + * @return PossiblyUpdatedStyle The eventually updated style */ - public function applyExtraStylesIfNeeded(Cell $cell) + public function applyExtraStylesIfNeeded(Cell $cell) : PossiblyUpdatedStyle { - $updatedStyle = $this->applyWrapTextIfCellContainsNewLine($cell); - - return $updatedStyle; + return $this->applyWrapTextIfCellContainsNewLine($cell); } /** @@ -69,21 +67,19 @@ class StyleManager implements StyleManagerInterface * on the Windows version of Excel... * * @param Cell $cell The cell the style should be applied to - * @return \Box\Spout\Common\Entity\Style\Style The eventually updated style + * @return PossiblyUpdatedStyle The eventually updated style */ - protected function applyWrapTextIfCellContainsNewLine(Cell $cell) + protected function applyWrapTextIfCellContainsNewLine(Cell $cell) : PossiblyUpdatedStyle { $cellStyle = $cell->getStyle(); // if the "wrap text" option is already set, no-op - if ($cellStyle->hasSetWrapText()) { - return $cellStyle; - } - - if ($cell->isString() && \strpos($cell->getValue(), "\n") !== false) { + if (!$cellStyle->hasSetWrapText() && $cell->isString() && \strpos($cell->getValue(), "\n") !== false) { $cellStyle->setShouldWrapText(); + + return new PossiblyUpdatedStyle($cellStyle, true); } - return $cellStyle; + return new PossiblyUpdatedStyle($cellStyle, false); } } diff --git a/src/Spout/Writer/Common/Manager/Style/StyleManagerInterface.php b/src/Spout/Writer/Common/Manager/Style/StyleManagerInterface.php index 312588e..6b320b1 100644 --- a/src/Spout/Writer/Common/Manager/Style/StyleManagerInterface.php +++ b/src/Spout/Writer/Common/Manager/Style/StyleManagerInterface.php @@ -24,7 +24,7 @@ interface StyleManagerInterface * Typically, set "wrap text" if a cell contains a new line. * * @param Cell $cell - * @return Style The updated style + * @return PossiblyUpdatedStyle The eventually updated style */ - public function applyExtraStylesIfNeeded(Cell $cell); + public function applyExtraStylesIfNeeded(Cell $cell) : PossiblyUpdatedStyle; } diff --git a/src/Spout/Writer/Common/Manager/Style/StyleRegistry.php b/src/Spout/Writer/Common/Manager/Style/StyleRegistry.php index d9e315f..6b439a7 100644 --- a/src/Spout/Writer/Common/Manager/Style/StyleRegistry.php +++ b/src/Spout/Writer/Common/Manager/Style/StyleRegistry.php @@ -36,9 +36,9 @@ class StyleRegistry { $serializedStyle = $this->serialize($style); - if (!$this->hasStyleAlreadyBeenRegistered($style)) { + if (!$this->hasSerializedStyleAlreadyBeenRegistered($serializedStyle)) { $nextStyleId = \count($this->serializedStyleToStyleIdMappingTable); - $style->setId($nextStyleId); + $style->markAsRegistered($nextStyleId); $this->serializedStyleToStyleIdMappingTable[$serializedStyle] = $nextStyleId; $this->styleIdToStyleMappingTable[$nextStyleId] = $style; @@ -48,15 +48,13 @@ class StyleRegistry } /** - * Returns whether the given style has already been registered. + * Returns whether the serialized style has already been registered. * - * @param Style $style + * @param string $serializedStyle The serialized style * @return bool */ - protected function hasStyleAlreadyBeenRegistered(Style $style) + protected function hasSerializedStyleAlreadyBeenRegistered(string $serializedStyle) { - $serializedStyle = $this->serialize($style); - // Using isset here because it is way faster than array_key_exists... return isset($this->serializedStyleToStyleIdMappingTable[$serializedStyle]); } @@ -101,13 +99,13 @@ class StyleRegistry */ public function serialize(Style $style) { - // In order to be able to properly compare style, set static ID value + // In order to be able to properly compare style, set static ID value and reset registration $currentId = $style->getId(); - $style->setId(0); + $style->unmarkAsRegistered(); $serializedStyle = \serialize($style); - $style->setId($currentId); + $style->markAsRegistered($currentId); return $serializedStyle; } diff --git a/src/Spout/Writer/ODS/Manager/Style/StyleRegistry.php b/src/Spout/Writer/ODS/Manager/Style/StyleRegistry.php index 6c580d4..42484f2 100644 --- a/src/Spout/Writer/ODS/Manager/Style/StyleRegistry.php +++ b/src/Spout/Writer/ODS/Manager/Style/StyleRegistry.php @@ -22,6 +22,10 @@ class StyleRegistry extends \Box\Spout\Writer\Common\Manager\Style\StyleRegistry */ public function registerStyle(Style $style) { + if ($style->isRegistered()) { + return $style; + } + $registeredStyle = parent::registerStyle($style); $this->usedFontsSet[$style->getFontName()] = true; diff --git a/src/Spout/Writer/ODS/Manager/WorksheetManager.php b/src/Spout/Writer/ODS/Manager/WorksheetManager.php index 38cd6c5..544945b 100644 --- a/src/Spout/Writer/ODS/Manager/WorksheetManager.php +++ b/src/Spout/Writer/ODS/Manager/WorksheetManager.php @@ -10,6 +10,7 @@ use Box\Spout\Common\Exception\IOException; use Box\Spout\Common\Helper\Escaper\ODS as ODSEscaper; use Box\Spout\Common\Helper\StringHelper; use Box\Spout\Writer\Common\Entity\Worksheet; +use Box\Spout\Writer\Common\Manager\RegisteredStyle; use Box\Spout\Writer\Common\Manager\Style\StyleMerger; use Box\Spout\Writer\Common\Manager\WorksheetManagerInterface; use Box\Spout\Writer\ODS\Manager\Style\StyleManager; @@ -104,8 +105,8 @@ class WorksheetManager implements WorksheetManagerInterface * * @param Worksheet $worksheet The worksheet to add the row to * @param Row $row The row to be added - * @throws IOException If the data cannot be written * @throws InvalidArgumentException If a cell value's type is not supported + * @throws IOException If the data cannot be written * @return void */ public function addRow(Worksheet $worksheet, Row $row) @@ -125,7 +126,13 @@ class WorksheetManager implements WorksheetManagerInterface $nextCell = isset($cells[$nextCellIndex]) ? $cells[$nextCellIndex] : null; if ($nextCell === null || $cell->getValue() !== $nextCell->getValue()) { - $data .= $this->applyStyleAndGetCellXML($cell, $rowStyle, $currentCellIndex, $nextCellIndex); + $registeredStyle = $this->applyStyleAndRegister($cell, $rowStyle); + $cellStyle = $registeredStyle->getStyle(); + if ($registeredStyle->isMatchingRowStyle()) { + $rowStyle = $cellStyle; // Replace actual rowStyle (possibly with null id) by registered style (with id) + } + + $data .= $this->getCellXMLWithStyle($cell, $cellStyle, $currentCellIndex, $nextCellIndex); $currentCellIndex = $nextCellIndex; } @@ -146,24 +153,46 @@ class WorksheetManager implements WorksheetManagerInterface /** * Applies styles to the given style, merging the cell's style with its row's style - * Then builds and returns xml for the cell. * * @param Cell $cell * @param Style $rowStyle - * @param int $currentCellIndex - * @param int $nextCellIndex * @throws InvalidArgumentException If a cell value's type is not supported - * @return string + * @return RegisteredStyle */ - private function applyStyleAndGetCellXML(Cell $cell, Style $rowStyle, $currentCellIndex, $nextCellIndex) + private function applyStyleAndRegister(Cell $cell, Style $rowStyle) : RegisteredStyle { - // Apply row and extra styles - $mergedCellAndRowStyle = $this->styleMerger->merge($cell->getStyle(), $rowStyle); - $cell->setStyle($mergedCellAndRowStyle); - $newCellStyle = $this->styleManager->applyExtraStylesIfNeeded($cell); + $isMatchingRowStyle = false; + if ($cell->getStyle()->isEmpty()) { + $cell->setStyle($rowStyle); - $registeredStyle = $this->styleManager->registerStyle($newCellStyle); - $styleIndex = $registeredStyle->getId() + 1; // 1-based + $possiblyUpdatedStyle = $this->styleManager->applyExtraStylesIfNeeded($cell); + + if ($possiblyUpdatedStyle->isUpdated()) { + $registeredStyle = $this->styleManager->registerStyle($possiblyUpdatedStyle->getStyle()); + } else { + $registeredStyle = $this->styleManager->registerStyle($rowStyle); + $isMatchingRowStyle = true; + } + } else { + $mergedCellAndRowStyle = $this->styleMerger->merge($cell->getStyle(), $rowStyle); + $cell->setStyle($mergedCellAndRowStyle); + + $possiblyUpdatedStyle = $this->styleManager->applyExtraStylesIfNeeded($cell); + if ($possiblyUpdatedStyle->isUpdated()) { + $newCellStyle = $possiblyUpdatedStyle->getStyle(); + } else { + $newCellStyle = $mergedCellAndRowStyle; + } + + $registeredStyle = $this->styleManager->registerStyle($newCellStyle); + } + + return new RegisteredStyle($registeredStyle, $isMatchingRowStyle); + } + + private function getCellXMLWithStyle(Cell $cell, Style $style, int $currentCellIndex, int $nextCellIndex) : string + { + $styleIndex = $style->getId() + 1; // 1-based $numTimesValueRepeated = ($nextCellIndex - $currentCellIndex); @@ -197,7 +226,8 @@ class WorksheetManager implements WorksheetManagerInterface $data .= ''; } elseif ($cell->isBoolean()) { - $data .= ' office:value-type="boolean" calcext:value-type="boolean" office:boolean-value="' . $cell->getValue() . '">'; + $value = $cell->getValue() ? 'true' : 'false'; // boolean-value spec: http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#datatype-boolean + $data .= ' office:value-type="boolean" calcext:value-type="boolean" office:boolean-value="' . $value . '">'; $data .= '' . $cell->getValue() . ''; $data .= ''; } elseif ($cell->isNumeric()) { diff --git a/src/Spout/Writer/WriterAbstract.php b/src/Spout/Writer/WriterAbstract.php index bbaa735..36a583f 100644 --- a/src/Spout/Writer/WriterAbstract.php +++ b/src/Spout/Writer/WriterAbstract.php @@ -123,9 +123,26 @@ abstract class WriterAbstract implements WriterInterface // @see https://github.com/box/spout/issues/241 $this->globalFunctionsHelper->ob_end_clean(); - // Set headers + /* + * Set headers + * + * For newer browsers such as Firefox, Chrome, Opera, Safari, etc., they all support and use `filename*` + * specified by the new standard, even if they do not automatically decode filename; it does not matter; + * and for older versions of Internet Explorer, they are not recognized `filename*`, will automatically + * ignore it and use the old `filename` (the only minor flaw is that there must be an English suffix name). + * In this way, the multi-browser multi-language compatibility problem is perfectly solved, which does not + * require UA judgment and is more in line with the standard. + * + * @see https://github.com/box/spout/issues/745 + * @see https://tools.ietf.org/html/rfc6266 + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition + */ $this->globalFunctionsHelper->header('Content-Type: ' . static::$headerContentType); - $this->globalFunctionsHelper->header('Content-Disposition: attachment; filename="' . $this->outputFilePath . '"'); + $this->globalFunctionsHelper->header( + 'Content-Disposition: attachment; ' . + 'filename="' . rawurldecode($this->outputFilePath) . '"; ' . + 'filename*=UTF-8\'\'' . rawurldecode($this->outputFilePath) + ); /* * When forcing the download of a file over SSL,IE8 and lower browsers fail diff --git a/src/Spout/Writer/XLSX/Manager/Style/StyleRegistry.php b/src/Spout/Writer/XLSX/Manager/Style/StyleRegistry.php index ace607c..14eb986 100644 --- a/src/Spout/Writer/XLSX/Manager/Style/StyleRegistry.php +++ b/src/Spout/Writer/XLSX/Manager/Style/StyleRegistry.php @@ -119,6 +119,10 @@ class StyleRegistry extends \Box\Spout\Writer\Common\Manager\Style\StyleRegistry */ public function registerStyle(Style $style) { + if ($style->isRegistered()) { + return $style; + } + $registeredStyle = parent::registerStyle($style); $this->registerFill($registeredStyle); $this->registerFormat($registeredStyle); diff --git a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php index 7c33e06..51ded12 100644 --- a/src/Spout/Writer/XLSX/Manager/WorksheetManager.php +++ b/src/Spout/Writer/XLSX/Manager/WorksheetManager.php @@ -14,6 +14,7 @@ use Box\Spout\Writer\Common\Creator\InternalEntityFactory; use Box\Spout\Writer\Common\Entity\Options; use Box\Spout\Writer\Common\Entity\Worksheet; use Box\Spout\Writer\Common\Helper\CellHelper; +use Box\Spout\Writer\Common\Manager\RegisteredStyle; use Box\Spout\Writer\Common\Manager\ManagesCellSize; use Box\Spout\Writer\Common\Manager\RowManager; use Box\Spout\Writer\Common\Manager\Style\StyleMerger; @@ -185,7 +186,12 @@ EOD; $rowXML = ""; foreach ($row->getCells() as $columnIndexZeroBased => $cell) { - $rowXML .= $this->applyStyleAndGetCellXML($cell, $rowStyle, $rowIndexOneBased, $columnIndexZeroBased); + $registeredStyle = $this->applyStyleAndRegister($cell, $rowStyle); + $cellStyle = $registeredStyle->getStyle(); + if ($registeredStyle->isMatchingRowStyle()) { + $rowStyle = $cellStyle; // Replace actual rowStyle (possibly with null id) by registered style (with id) + } + $rowXML .= $this->getCellXML($rowIndexOneBased, $columnIndexZeroBased, $cell, $cellStyle->getId()); } $rowXML .= ''; @@ -198,26 +204,43 @@ EOD; /** * Applies styles to the given style, merging the cell's style with its row's style - * Then builds and returns xml for the cell. * * @param Cell $cell * @param Style $rowStyle - * @param int $rowIndexOneBased - * @param int $columnIndexZeroBased * * @throws InvalidArgumentException If the given value cannot be processed - * @return string + * @return RegisteredStyle */ - private function applyStyleAndGetCellXML(Cell $cell, Style $rowStyle, $rowIndexOneBased, $columnIndexZeroBased) + private function applyStyleAndRegister(Cell $cell, Style $rowStyle) : RegisteredStyle { - // Apply row and extra styles - $mergedCellAndRowStyle = $this->styleMerger->merge($cell->getStyle(), $rowStyle); - $cell->setStyle($mergedCellAndRowStyle); - $newCellStyle = $this->styleManager->applyExtraStylesIfNeeded($cell); + $isMatchingRowStyle = false; + if ($cell->getStyle()->isEmpty()) { + $cell->setStyle($rowStyle); - $registeredStyle = $this->styleManager->registerStyle($newCellStyle); + $possiblyUpdatedStyle = $this->styleManager->applyExtraStylesIfNeeded($cell); - return $this->getCellXML($rowIndexOneBased, $columnIndexZeroBased, $cell, $registeredStyle->getId()); + if ($possiblyUpdatedStyle->isUpdated()) { + $registeredStyle = $this->styleManager->registerStyle($possiblyUpdatedStyle->getStyle()); + } else { + $registeredStyle = $this->styleManager->registerStyle($rowStyle); + $isMatchingRowStyle = true; + } + } else { + $mergedCellAndRowStyle = $this->styleMerger->merge($cell->getStyle(), $rowStyle); + $cell->setStyle($mergedCellAndRowStyle); + + $possiblyUpdatedStyle = $this->styleManager->applyExtraStylesIfNeeded($cell); + + if ($possiblyUpdatedStyle->isUpdated()) { + $newCellStyle = $possiblyUpdatedStyle->getStyle(); + } else { + $newCellStyle = $mergedCellAndRowStyle; + } + + $registeredStyle = $this->styleManager->registerStyle($newCellStyle); + } + + return new RegisteredStyle($registeredStyle, $isMatchingRowStyle); } /** diff --git a/tests/Spout/Common/Entity/RowTest.php b/tests/Spout/Common/Entity/RowTest.php index 095025c..9aa12f6 100644 --- a/tests/Spout/Common/Entity/RowTest.php +++ b/tests/Spout/Common/Entity/RowTest.php @@ -122,6 +122,6 @@ class RowTest extends \PHPUnit\Framework\TestCase ->setStyle($this->getStyleMock()) ->setCells([]); - $this->assertInternalType('object', $row); + $this->assertInstanceOf(Row::class, $row); } } diff --git a/tests/Spout/Common/Helper/FileSystemHelperTest.php b/tests/Spout/Common/Helper/FileSystemHelperTest.php index f99ab30..7eb0183 100644 --- a/tests/Spout/Common/Helper/FileSystemHelperTest.php +++ b/tests/Spout/Common/Helper/FileSystemHelperTest.php @@ -16,7 +16,7 @@ class FileSystemHelperTest extends TestCase /** * @return void */ - public function setUp() + public function setUp() : void { $baseFolder = \sys_get_temp_dir(); $this->fileSystemHelper = new FileSystemHelper($baseFolder); diff --git a/tests/Spout/Common/Manager/OptionsManagerTest.php b/tests/Spout/Common/Manager/OptionsManagerTest.php index e2f0c5c..d5fe5d8 100644 --- a/tests/Spout/Common/Manager/OptionsManagerTest.php +++ b/tests/Spout/Common/Manager/OptionsManagerTest.php @@ -14,7 +14,7 @@ class OptionsManagerTest extends TestCase */ protected $optionsManager; - protected function setUp() + protected function setUp() : void { $this->optionsManager = new class() extends OptionsManagerAbstract { protected function getSupportedOptions() diff --git a/tests/Spout/Reader/ODS/ReaderTest.php b/tests/Spout/Reader/ODS/ReaderTest.php index ce56e4b..cd30ae5 100644 --- a/tests/Spout/Reader/ODS/ReaderTest.php +++ b/tests/Spout/Reader/ODS/ReaderTest.php @@ -295,6 +295,10 @@ class ReaderTest extends TestCase */ public function testReadShouldBeProtectedAgainstBillionLaughsAttack() { + if (function_exists('xdebug_code_coverage_started') && xdebug_code_coverage_started()) { + $this->markTestSkipped('test not compatible with code coverage'); + } + $startTime = microtime(true); $fileName = 'attack_billion_laughs.ods'; @@ -318,6 +322,10 @@ class ReaderTest extends TestCase */ public function testReadShouldBeProtectedAgainstQuadraticBlowupAttack() { + if (function_exists('xdebug_code_coverage_started') && xdebug_code_coverage_started()) { + $this->markTestSkipped('test not compatible with code coverage'); + } + $startTime = microtime(true); $fileName = 'attack_quadratic_blowup.ods'; diff --git a/tests/Spout/Reader/XLSX/Manager/SharedStringsManagerTest.php b/tests/Spout/Reader/XLSX/Manager/SharedStringsManagerTest.php index 2f85f34..f344b35 100644 --- a/tests/Spout/Reader/XLSX/Manager/SharedStringsManagerTest.php +++ b/tests/Spout/Reader/XLSX/Manager/SharedStringsManagerTest.php @@ -25,7 +25,7 @@ class SharedStringsManagerTest extends TestCase /** * @return void */ - public function setUp() + public function setUp() : void { $this->sharedStringsManager = null; } @@ -33,7 +33,7 @@ class SharedStringsManagerTest extends TestCase /** * @return void */ - public function tearDown() + public function tearDown() : void { if ($this->sharedStringsManager !== null) { $this->sharedStringsManager->cleanup(); diff --git a/tests/Spout/Reader/XLSX/ReaderTest.php b/tests/Spout/Reader/XLSX/ReaderTest.php index 51a7b0e..7d30f97 100644 --- a/tests/Spout/Reader/XLSX/ReaderTest.php +++ b/tests/Spout/Reader/XLSX/ReaderTest.php @@ -539,6 +539,10 @@ class ReaderTest extends TestCase */ public function testReadShouldBeProtectedAgainstQuadraticBlowupAttack() { + if (function_exists('xdebug_code_coverage_started') && xdebug_code_coverage_started()) { + $this->markTestSkipped('test not compatible with code coverage'); + } + $startTime = microtime(true); $this->getAllRowsForFile('attack_quadratic_blowup.xlsx'); diff --git a/tests/Spout/Writer/CSV/WriterPerfTest.php b/tests/Spout/Writer/CSV/WriterPerfTest.php index 4172bf5..cbfcae0 100644 --- a/tests/Spout/Writer/CSV/WriterPerfTest.php +++ b/tests/Spout/Writer/CSV/WriterPerfTest.php @@ -61,7 +61,7 @@ class WriterPerfTest extends TestCase */ private function getNumWrittenRows($resourcePath) { - $lineCountResult = `wc -l $resourcePath`; + $lineCountResult = shell_exec("wc -l $resourcePath"); return (int) $lineCountResult; } diff --git a/tests/Spout/Writer/CSV/WriterTest.php b/tests/Spout/Writer/CSV/WriterTest.php index 0b3b238..deb3f22 100644 --- a/tests/Spout/Writer/CSV/WriterTest.php +++ b/tests/Spout/Writer/CSV/WriterTest.php @@ -101,7 +101,7 @@ class WriterTest extends TestCase ]); $writtenContent = $this->writeToCsvFileAndReturnWrittenContent($allRows, 'csv_with_utf8_bom.csv'); - $this->assertContains(EncodingHelper::BOM_UTF8, $writtenContent, 'The CSV file should contain a UTF-8 BOM'); + $this->assertStringStartsWith(EncodingHelper::BOM_UTF8, $writtenContent, 'The CSV file should contain a UTF-8 BOM'); } /** @@ -114,7 +114,7 @@ class WriterTest extends TestCase ]); $writtenContent = $this->writeToCsvFileAndReturnWrittenContent($allRows, 'csv_no_bom.csv', ',', '"', false); - $this->assertNotContains(EncodingHelper::BOM_UTF8, $writtenContent, 'The CSV file should not contain a UTF-8 BOM'); + $this->assertStringNotContainsString(EncodingHelper::BOM_UTF8, $writtenContent, 'The CSV file should not contain a UTF-8 BOM'); } /** diff --git a/tests/Spout/Writer/Common/Entity/SheetTest.php b/tests/Spout/Writer/Common/Entity/SheetTest.php index cb19d6f..e0cf8ee 100644 --- a/tests/Spout/Writer/Common/Entity/SheetTest.php +++ b/tests/Spout/Writer/Common/Entity/SheetTest.php @@ -18,7 +18,7 @@ class SheetTest extends TestCase /** * @return void */ - public function setUp() + public function setUp() : void { $this->sheetManager = new SheetManager(new StringHelper()); } diff --git a/tests/Spout/Writer/Common/Manager/Style/StyleManagerTest.php b/tests/Spout/Writer/Common/Manager/Style/StyleManagerTest.php index 82292bb..5bbbe5c 100644 --- a/tests/Spout/Writer/Common/Manager/Style/StyleManagerTest.php +++ b/tests/Spout/Writer/Common/Manager/Style/StyleManagerTest.php @@ -14,7 +14,7 @@ class StyleManagerTest extends TestCase /** * @return StyleManager */ - private function getStyleManager() + private function getStyleManager() : StyleManager { $style = (new StyleBuilder())->build(); $styleRegistry = new StyleRegistry($style); @@ -22,31 +22,37 @@ class StyleManagerTest extends TestCase return new StyleManager($styleRegistry); } - /** - * @return void - */ - public function testApplyExtraStylesIfNeededShouldApplyWrapTextIfCellContainsNewLine() + public function testApplyExtraStylesIfNeededShouldApplyWrapTextIfCellContainsNewLine() : void { $style = (new StyleBuilder())->build(); $this->assertFalse($style->shouldWrapText()); $styleManager = $this->getStyleManager(); - $updatedStyle = $styleManager->applyExtraStylesIfNeeded(new Cell("multi\nlines", $style)); + $possiblyUpdatedStyle = $styleManager->applyExtraStylesIfNeeded(new Cell("multi\nlines", $style)); - $this->assertTrue($updatedStyle->shouldWrapText()); + $this->assertTrue($possiblyUpdatedStyle->isUpdated()); + $this->assertTrue($possiblyUpdatedStyle->getStyle()->shouldWrapText()); } - /** - * @return void - */ - public function testApplyExtraStylesIfNeededShouldDoNothingIfWrapTextAlreadyApplied() + public function testApplyExtraStylesIfNeededShouldReturnNullIfWrapTextNotNeeded() : void + { + $style = (new StyleBuilder())->build(); + $this->assertFalse($style->shouldWrapText()); + + $styleManager = $this->getStyleManager(); + $possiblyUpdatedStyle = $styleManager->applyExtraStylesIfNeeded(new Cell('oneline', $style)); + + $this->assertFalse($possiblyUpdatedStyle->isUpdated()); + } + + public function testApplyExtraStylesIfNeededShouldReturnNullIfWrapTextAlreadyApplied() : void { $style = (new StyleBuilder())->setShouldWrapText()->build(); $this->assertTrue($style->shouldWrapText()); $styleManager = $this->getStyleManager(); - $updatedStyle = $styleManager->applyExtraStylesIfNeeded(new Cell("multi\nlines", $style)); + $possiblyUpdatedStyle = $styleManager->applyExtraStylesIfNeeded(new Cell("multi\nlines", $style)); - $this->assertTrue($updatedStyle->shouldWrapText()); + $this->assertFalse($possiblyUpdatedStyle->isUpdated()); } } diff --git a/tests/Spout/Writer/Common/Manager/Style/StyleMergerTest.php b/tests/Spout/Writer/Common/Manager/Style/StyleMergerTest.php index 46820c0..b7c1607 100644 --- a/tests/Spout/Writer/Common/Manager/Style/StyleMergerTest.php +++ b/tests/Spout/Writer/Common/Manager/Style/StyleMergerTest.php @@ -18,7 +18,7 @@ class StyleMergerTest extends TestCase /** * @return void */ - public function setUp() + public function setUp() : void { $this->styleMerger = new StyleMerger(); } diff --git a/tests/Spout/Writer/Common/Manager/Style/StyleRegistryTest.php b/tests/Spout/Writer/Common/Manager/Style/StyleRegistryTest.php index 41cc571..ac78c9e 100644 --- a/tests/Spout/Writer/Common/Manager/Style/StyleRegistryTest.php +++ b/tests/Spout/Writer/Common/Manager/Style/StyleRegistryTest.php @@ -20,7 +20,7 @@ class StyleRegistryTest extends TestCase /** * @return void */ - public function setUp() + public function setUp() : void { $this->defaultStyle = (new StyleBuilder())->build(); $this->styleRegistry = new StyleRegistry($this->defaultStyle); diff --git a/tests/Spout/Writer/ODS/SheetTest.php b/tests/Spout/Writer/ODS/SheetTest.php index b5fec7b..f94f63c 100644 --- a/tests/Spout/Writer/ODS/SheetTest.php +++ b/tests/Spout/Writer/ODS/SheetTest.php @@ -90,7 +90,7 @@ class SheetTest extends TestCase $pathToContentFile = $resourcePath . '#content.xml'; $xmlContents = file_get_contents('zip://' . $pathToContentFile); - $this->assertContains(' table:display="false"', $xmlContents, 'The sheet visibility should have been changed to "hidden"'); + $this->assertStringContainsString(' table:display="false"', $xmlContents, 'The sheet visibility should have been changed to "hidden"'); } public function testThrowsIfWorkbookIsNotInitialized() @@ -285,6 +285,6 @@ class SheetTest extends TestCase $pathToWorkbookFile = $resourcePath . '#content.xml'; $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); - $this->assertContains("table:name=\"$expectedName\"", $xmlContents, $message); + $this->assertStringContainsString("table:name=\"$expectedName\"", $xmlContents, $message); } } diff --git a/tests/Spout/Writer/ODS/WriterPerfTest.php b/tests/Spout/Writer/ODS/WriterPerfTest.php index 40c4ee0..5917b49 100644 --- a/tests/Spout/Writer/ODS/WriterPerfTest.php +++ b/tests/Spout/Writer/ODS/WriterPerfTest.php @@ -88,7 +88,7 @@ class WriterPerfTest extends TestCase copy($pathToContentXmlFile, $tmpFile); // Get the last 200 characters - $lastCharacters = `tail -c 200 $tmpFile`; + $lastCharacters = shell_exec("tail -c 200 $tmpFile"); // remove the temporary file unlink($tmpFile); diff --git a/tests/Spout/Writer/ODS/WriterTest.php b/tests/Spout/Writer/ODS/WriterTest.php index b30a8f6..31dcccf 100644 --- a/tests/Spout/Writer/ODS/WriterTest.php +++ b/tests/Spout/Writer/ODS/WriterTest.php @@ -547,7 +547,7 @@ class WriterTest extends TestCase $pathToContentFile = $resourcePath . '#content.xml'; $xmlContents = file_get_contents('zip://' . $pathToContentFile); - $this->assertContains($value, $xmlContents, $message); + $this->assertStringContainsString($value, $xmlContents, $message); } /** @@ -562,7 +562,7 @@ class WriterTest extends TestCase $sheetXmlAsString = $this->getSheetXmlNodeAsString($fileName, $sheetIndex); $valueAsXmlString = "$value"; - $this->assertContains($valueAsXmlString, $sheetXmlAsString, $message); + $this->assertStringContainsString($valueAsXmlString, $sheetXmlAsString, $message); } /** @@ -577,7 +577,7 @@ class WriterTest extends TestCase $sheetXmlAsString = $this->getSheetXmlNodeAsString($fileName, $sheetIndex); $valueAsXmlString = "$value"; - $this->assertNotContains($valueAsXmlString, $sheetXmlAsString, $message); + $this->assertStringNotContainsString($valueAsXmlString, $sheetXmlAsString, $message); } /** diff --git a/tests/Spout/Writer/ODS/WriterWithStyleTest.php b/tests/Spout/Writer/ODS/WriterWithStyleTest.php index dcdd364..75177da 100644 --- a/tests/Spout/Writer/ODS/WriterWithStyleTest.php +++ b/tests/Spout/Writer/ODS/WriterWithStyleTest.php @@ -30,7 +30,7 @@ class WriterWithStyleTest extends TestCase /** * @return void */ - public function setUp() + public function setUp() : void { $this->defaultStyle = (new StyleBuilder())->build(); } diff --git a/tests/Spout/Writer/XLSX/SheetTest.php b/tests/Spout/Writer/XLSX/SheetTest.php index f0caf1b..79033c2 100644 --- a/tests/Spout/Writer/XLSX/SheetTest.php +++ b/tests/Spout/Writer/XLSX/SheetTest.php @@ -90,7 +90,7 @@ class SheetTest extends TestCase $pathToWorkbookFile = $resourcePath . '#xl/workbook.xml'; $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); - $this->assertContains(' state="hidden"', $xmlContents, 'The sheet visibility should have been changed to "hidden"'); + $this->assertStringContainsString(' state="hidden"', $xmlContents, 'The sheet visibility should have been changed to "hidden"'); } public function testThrowsIfWorkbookIsNotInitialized() @@ -299,6 +299,6 @@ class SheetTest extends TestCase $pathToWorkbookFile = $resourcePath . '#xl/workbook.xml'; $xmlContents = file_get_contents('zip://' . $pathToWorkbookFile); - $this->assertContains("assertStringContainsString("assertContains((string) $inlineData, $xmlContents, $message); + $this->assertStringContainsString((string) $inlineData, $xmlContents, $message); } /** @@ -624,7 +624,7 @@ class WriterTest extends TestCase $pathToSheetFile = $resourcePath . '#xl/worksheets/sheet' . $sheetIndex . '.xml'; $xmlContents = file_get_contents('zip://' . $pathToSheetFile); - $this->assertNotContains((string) $inlineData, $xmlContents, $message); + $this->assertStringNotContainsString((string) $inlineData, $xmlContents, $message); } /** @@ -639,6 +639,6 @@ class WriterTest extends TestCase $pathToSharedStringsFile = $resourcePath . '#xl/sharedStrings.xml'; $xmlContents = file_get_contents('zip://' . $pathToSharedStringsFile); - $this->assertContains($sharedString, $xmlContents, $message); + $this->assertStringContainsString($sharedString, $xmlContents, $message); } } diff --git a/tests/Spout/Writer/XLSX/WriterWithStyleTest.php b/tests/Spout/Writer/XLSX/WriterWithStyleTest.php index da0aec2..2571df4 100644 --- a/tests/Spout/Writer/XLSX/WriterWithStyleTest.php +++ b/tests/Spout/Writer/XLSX/WriterWithStyleTest.php @@ -32,7 +32,7 @@ class WriterWithStyleTest extends TestCase /** * @return void */ - public function setUp() + public function setUp() : void { $this->defaultStyle = (new StyleBuilder())->build(); }