From 2dc9fc6bb7abc0ad6fa4db33a6e5289711d8f616 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Fri, 18 Mar 2022 22:38:24 +0100 Subject: [PATCH 1/2] Move DataValidation switch statements into a dedicated helper class --- phpstan-baseline.neon | 16 +--- src/PhpSpreadsheet/Reader/Xls.php | 85 ++----------------- .../Reader/Xls/DataValidationHelper.php | 72 ++++++++++++++++ 3 files changed, 78 insertions(+), 95 deletions(-) create mode 100644 src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ab910eee..9ecc0f01 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2300,16 +2300,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Reader/Xls.php - - - message: "#^Parameter \\#1 \\$errorStyle of method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataValidation\\:\\:setErrorStyle\\(\\) expects string, int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Parameter \\#1 \\$operator of method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataValidation\\:\\:setOperator\\(\\) expects string, int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - message: "#^Parameter \\#1 \\$showSummaryBelow of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:setShowSummaryBelow\\(\\) expects bool, int given\\.$#" count: 1 @@ -2320,11 +2310,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xls.php - - - message: "#^Parameter \\#1 \\$type of method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataValidation\\:\\:setType\\(\\) expects string, int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - message: "#^Parameter \\#2 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReadFilter\\:\\:readCell\\(\\) expects int, string given\\.$#" count: 1 @@ -5484,3 +5469,4 @@ parameters: message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Xlfn\\:\\:addXlfn\\(\\) should return string but returns string\\|null\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php + diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index 0fd05c87..bff2d41e 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -4776,57 +4776,11 @@ class Xls extends BaseReader // bit: 0-3; mask: 0x0000000F; type $type = (0x0000000F & $options) >> 0; - switch ($type) { - case 0x00: - $type = DataValidation::TYPE_NONE; - - break; - case 0x01: - $type = DataValidation::TYPE_WHOLE; - - break; - case 0x02: - $type = DataValidation::TYPE_DECIMAL; - - break; - case 0x03: - $type = DataValidation::TYPE_LIST; - - break; - case 0x04: - $type = DataValidation::TYPE_DATE; - - break; - case 0x05: - $type = DataValidation::TYPE_TIME; - - break; - case 0x06: - $type = DataValidation::TYPE_TEXTLENGTH; - - break; - case 0x07: - $type = DataValidation::TYPE_CUSTOM; - - break; - } + $type = Xls\DataValidationHelper::type($type); // bit: 4-6; mask: 0x00000070; error type $errorStyle = (0x00000070 & $options) >> 4; - switch ($errorStyle) { - case 0x00: - $errorStyle = DataValidation::STYLE_STOP; - - break; - case 0x01: - $errorStyle = DataValidation::STYLE_WARNING; - - break; - case 0x02: - $errorStyle = DataValidation::STYLE_INFORMATION; - - break; - } + $errorStyle = Xls\DataValidationHelper::errorStyle($errorStyle); // bit: 7; mask: 0x00000080; 1= formula is explicit (only applies to list) // I have only seen cases where this is 1 @@ -4846,39 +4800,10 @@ class Xls extends BaseReader // bit: 20-23; mask: 0x00F00000; condition operator $operator = (0x00F00000 & $options) >> 20; - switch ($operator) { - case 0x00: - $operator = DataValidation::OPERATOR_BETWEEN; + $operator = Xls\DataValidationHelper::operator($operator); - break; - case 0x01: - $operator = DataValidation::OPERATOR_NOTBETWEEN; - - break; - case 0x02: - $operator = DataValidation::OPERATOR_EQUAL; - - break; - case 0x03: - $operator = DataValidation::OPERATOR_NOTEQUAL; - - break; - case 0x04: - $operator = DataValidation::OPERATOR_GREATERTHAN; - - break; - case 0x05: - $operator = DataValidation::OPERATOR_LESSTHAN; - - break; - case 0x06: - $operator = DataValidation::OPERATOR_GREATERTHANOREQUAL; - - break; - case 0x07: - $operator = DataValidation::OPERATOR_LESSTHANOREQUAL; - - break; + if ($type === null || $errorStyle === null || $operator === null) { + return; } // offset: 4; size: var; title of the prompt box diff --git a/src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php b/src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php new file mode 100644 index 00000000..02f844e3 --- /dev/null +++ b/src/PhpSpreadsheet/Reader/Xls/DataValidationHelper.php @@ -0,0 +1,72 @@ + + */ + private static $types = [ + 0x00 => DataValidation::TYPE_NONE, + 0x01 => DataValidation::TYPE_WHOLE, + 0x02 => DataValidation::TYPE_DECIMAL, + 0x03 => DataValidation::TYPE_LIST, + 0x04 => DataValidation::TYPE_DATE, + 0x05 => DataValidation::TYPE_TIME, + 0x06 => DataValidation::TYPE_TEXTLENGTH, + 0x07 => DataValidation::TYPE_CUSTOM, + ]; + + /** + * @var array + */ + private static $errorStyles = [ + 0x00 => DataValidation::STYLE_STOP, + 0x01 => DataValidation::STYLE_WARNING, + 0x02 => DataValidation::STYLE_INFORMATION, + ]; + + /** + * @var array + */ + private static $operators = [ + 0x00 => DataValidation::OPERATOR_BETWEEN, + 0x01 => DataValidation::OPERATOR_NOTBETWEEN, + 0x02 => DataValidation::OPERATOR_EQUAL, + 0x03 => DataValidation::OPERATOR_NOTEQUAL, + 0x04 => DataValidation::OPERATOR_GREATERTHAN, + 0x05 => DataValidation::OPERATOR_LESSTHAN, + 0x06 => DataValidation::OPERATOR_GREATERTHANOREQUAL, + 0x07 => DataValidation::OPERATOR_LESSTHANOREQUAL, + ]; + + public static function type(int $type): ?string + { + if (isset(self::$types[$type])) { + return self::$types[$type]; + } + + return null; + } + + public static function errorStyle(int $errorStyle): ?string + { + if (isset(self::$errorStyles[$errorStyle])) { + return self::$errorStyles[$errorStyle]; + } + + return null; + } + + public static function operator(int $operator): ?string + { + if (isset(self::$operators[$operator])) { + return self::$operators[$operator]; + } + + return null; + } +} From c73bb612e0445ebbf0896128f66bc3bbe31de1c4 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sat, 19 Mar 2022 12:04:14 +0100 Subject: [PATCH 2/2] Unit tests for Xls Reader DataValidation --- .../Reader/Xls/DataValidationTest.php | 60 ++++++++++++++++++ tests/data/Reader/XLS/DataValidation.xls | Bin 0 -> 26112 bytes 2 files changed, 60 insertions(+) create mode 100644 tests/PhpSpreadsheetTests/Reader/Xls/DataValidationTest.php create mode 100644 tests/data/Reader/XLS/DataValidation.xls diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/DataValidationTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/DataValidationTest.php new file mode 100644 index 00000000..bdefa17e --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xls/DataValidationTest.php @@ -0,0 +1,60 @@ +load($filename); + $this->sheet = $spreadsheet->getActiveSheet(); + } + + /** + * @dataProvider dataValidationProvider + */ + public function testDataValidation(string $expectedRange, array $expectedRule): void + { + $hasDataValidation = $this->sheet->dataValidationExists($expectedRange); + self::assertTrue($hasDataValidation); + + $dataValidation = $this->sheet->getDataValidation($expectedRange); + self::assertSame($expectedRule['type'], $dataValidation->getType()); + self::assertSame($expectedRule['operator'], $dataValidation->getOperator()); + self::assertSame($expectedRule['formula'], $dataValidation->getFormula1()); + } + + public function dataValidationProvider(): array + { + return [ + [ + 'B2', + [ + 'type' => DataValidation::TYPE_WHOLE, + 'operator' => DataValidation::OPERATOR_GREATERTHANOREQUAL, + 'formula' => '18', + ], + ], + [ + 'B3', + [ + 'type' => DataValidation::TYPE_LIST, + 'operator' => DataValidation::OPERATOR_BETWEEN, + 'formula' => '"Blocked,Pending,Approved"', + ], + ], + ]; + } +} diff --git a/tests/data/Reader/XLS/DataValidation.xls b/tests/data/Reader/XLS/DataValidation.xls new file mode 100644 index 0000000000000000000000000000000000000000..44e9d1d3c7bd57d4fa58e49fdb68d6b2b12bf5f1 GIT binary patch literal 26112 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 D1Cl>t literal 0 HcmV?d00001