From 64f354eb6e31f0e98e62680cb0a9a4fbf726bb65 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sun, 5 May 2024 04:37:46 -0700 Subject: [PATCH 1/2] Better Definitions for Mixed Parameters and Values Part 1 of Many Improve documentation within program by making explicit what types of values are allowed for variables described as "mixed". In order to avoid broken functionality, this is done mainly through doc-blocks. This will get us closer to Phpstan Level 9, but many changes will be needed before we can consider that. Executable code change is to add 2 new methods to Cell - `getValueString` and `getCalculatedValueString`, which are the same as the methods without the String suffix, except that they always return a string result. These are invoked at several places in the code where it makes sense, in particular by Writer code. --- .../Calculation/Engineering/ConvertUOM.php | 8 ++++---- .../Calculation/MathTrig/Arabic.php | 2 +- .../Calculation/TextData/Format.php | 2 ++ src/PhpSpreadsheet/Cell/Cell.php | 17 +++++++++++++++++ src/PhpSpreadsheet/Shared/Font.php | 4 +++- src/PhpSpreadsheet/Shared/StringHelper.php | 2 +- src/PhpSpreadsheet/Style/NumberFormat.php | 4 +++- .../Style/NumberFormat/Formatter.php | 1 + .../Style/NumberFormat/FractionFormatter.php | 1 + src/PhpSpreadsheet/Worksheet/Table.php | 2 +- src/PhpSpreadsheet/Worksheet/Table/Column.php | 2 +- src/PhpSpreadsheet/Worksheet/Worksheet.php | 2 +- src/PhpSpreadsheet/Writer/Csv.php | 4 ++++ src/PhpSpreadsheet/Writer/Html.php | 3 ++- src/PhpSpreadsheet/Writer/Ods/Content.php | 18 +++++++++--------- src/PhpSpreadsheet/Writer/Xlsx/Table.php | 2 +- .../Cell/CellAddressTest.php | 2 +- .../Document/PropertiesTest.php | 2 +- .../Style/NumberFormatTest.php | 6 ++++++ 19 files changed, 60 insertions(+), 24 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php index 523ff21d3..5fc32badb 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php @@ -27,7 +27,7 @@ class ConvertUOM /** * Details of the Units of measure that can be used in CONVERTUOM(). * - * @var mixed[] + * @var array */ private static array $conversionUnits = [ // Weight and Mass @@ -201,7 +201,7 @@ class ConvertUOM /** * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM(). * - * @var mixed[] + * @var array */ private static array $conversionMultipliers = [ 'Y' => ['multiplier' => 1E24, 'name' => 'yotta'], @@ -230,7 +230,7 @@ class ConvertUOM /** * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM(). * - * @var mixed[] + ** @var array */ private static array $binaryConversionMultipliers = [ 'Yi' => ['multiplier' => 2 ** 80, 'name' => 'yobi'], @@ -246,7 +246,7 @@ class ConvertUOM /** * Details of the Units of measure conversion factors, organised by group. * - * @var mixed[] + * @var array> */ private static array $unitConversions = [ // Conversion uses gram (g) as an intermediate unit diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php b/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php index 57918a1f9..98c3e3dce 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php @@ -53,7 +53,7 @@ class Arabic * Excel Function: * ARABIC(text) * - * @param mixed $roman Should be a string, or can be an array of strings + * @param string|string[] $roman Should be a string, or can be an array of strings * * @return array|int|string the arabic numberal contrived from the roman numeral * If an array of numbers is passed as the argument, then the returned result will also be an array diff --git a/src/PhpSpreadsheet/Calculation/TextData/Format.php b/src/PhpSpreadsheet/Calculation/TextData/Format.php index 0fa67d7bb..40335ced7 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Format.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Format.php @@ -56,6 +56,7 @@ class Format if ($value < 0) { $round = 0 - $round; } + /** @var float|int|string */ $value = MathTrig\Round::multiple($value, $round); } $mask = "{$mask};-{$mask}"; @@ -129,6 +130,7 @@ class Format if (!is_numeric($value) && Date::isDateTimeFormatCode($format)) { $value1 = DateTimeExcel\DateValue::fromString($value); $value2 = DateTimeExcel\TimeValue::fromString($value); + /** @var float|int|string */ $value = (is_numeric($value1) && is_numeric($value2)) ? ($value1 + $value2) : (is_numeric($value1) ? $value2 : $value1); } diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index 4cbdbbe92..3dc6c2eab 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -175,6 +175,13 @@ class Cell implements Stringable return $this->value; } + public function getValueString(): string + { + $value = $this->value; + + return ($value === '' || is_scalar($value) || $value instanceof Stringable) ? "$value" : ''; + } + /** * Get cell value with formatting. */ @@ -336,6 +343,16 @@ class Cell implements Stringable return $result; } + /** + * Get calculated cell value converted to string. + */ + public function getCalculatedValueString(): string + { + $value = $this->getCalculatedValue(); + + return ($value === '' || is_scalar($value) || $value instanceof Stringable) ? "$value" : ''; + } + /** * Get calculated cell value. * diff --git a/src/PhpSpreadsheet/Shared/Font.php b/src/PhpSpreadsheet/Shared/Font.php index 01af7ba18..8a1225b1c 100644 --- a/src/PhpSpreadsheet/Shared/Font.php +++ b/src/PhpSpreadsheet/Shared/Font.php @@ -695,8 +695,10 @@ class Font $it, RecursiveIteratorIterator::LEAVES_ONLY, RecursiveIteratorIterator::CATCH_GET_CHILD - ) as $file + ) as $filex ) { + /** @var string */ + $file = $filex; if (basename($file) === $desiredFont) { $fontPath = $file; diff --git a/src/PhpSpreadsheet/Shared/StringHelper.php b/src/PhpSpreadsheet/Shared/StringHelper.php index 18f8d0273..aac3836ce 100644 --- a/src/PhpSpreadsheet/Shared/StringHelper.php +++ b/src/PhpSpreadsheet/Shared/StringHelper.php @@ -346,7 +346,7 @@ class StringHelper * see OpenOffice.org's Documentation of the Microsoft Excel File Format, sect. 2.5.3. * * @param string $textValue UTF-8 encoded string - * @param mixed[] $arrcRuns Details of rich text runs in $value + * @param array $arrcRuns Details of rich text runs in $value */ public static function UTF8toBIFF8UnicodeShort(string $textValue, array $arrcRuns = []): string { diff --git a/src/PhpSpreadsheet/Style/NumberFormat.php b/src/PhpSpreadsheet/Style/NumberFormat.php index b344da64b..9c9a54560 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat.php +++ b/src/PhpSpreadsheet/Style/NumberFormat.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Style; +use PhpOffice\PhpSpreadsheet\RichText\RichText; + class NumberFormat extends Supervisor { // Pre-defined formats @@ -453,7 +455,7 @@ class NumberFormat extends Supervisor /** * Convert a value in a pre-defined format to a PHP string. * - * @param mixed $value Value to format + * @param null|bool|float|int|RichText|string $value Value to format * @param string $format Format code: see = self::FORMAT_* for predefined values; * or can be any valid MS Excel custom format string * @param ?array $callBack Callback function for additional formatting of string diff --git a/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php b/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php index 984aa174e..f2d492e5d 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php +++ b/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php @@ -42,6 +42,7 @@ class Formatter extends BaseFormatter }; } + /** @param float|int|string $value value to be formatted */ private static function splitFormatForSectionSelection(array $sections, mixed $value): array { // Extract the relevant section depending on whether number is positive, negative, or zero? diff --git a/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php b/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php index 504e77ac6..ff80aa2f5 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php +++ b/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php @@ -6,6 +6,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class FractionFormatter extends BaseFormatter { + /** @param null|bool|float|int|string $value value to be formatted */ public static function format(mixed $value, string $format): string { $format = self::stripQuotes($format); diff --git a/src/PhpSpreadsheet/Worksheet/Table.php b/src/PhpSpreadsheet/Worksheet/Table.php index 44ee36ff8..ab05f5d5e 100644 --- a/src/PhpSpreadsheet/Worksheet/Table.php +++ b/src/PhpSpreadsheet/Worksheet/Table.php @@ -178,7 +178,7 @@ class Table implements Stringable foreach ($worksheet->getCoordinates(false) as $coordinate) { $cell = $worksheet->getCell($coordinate); if ($cell->getDataType() === DataType::TYPE_FORMULA) { - $formula = $cell->getValue(); + $formula = $cell->getValueString(); if (preg_match($pattern, $formula) === 1) { $formula = preg_replace($pattern, "{$newName}[", $formula); $cell->setValueExplicit($formula, DataType::TYPE_FORMULA); diff --git a/src/PhpSpreadsheet/Worksheet/Table/Column.php b/src/PhpSpreadsheet/Worksheet/Table/Column.php index 8f8f55b95..257e3e390 100644 --- a/src/PhpSpreadsheet/Worksheet/Table/Column.php +++ b/src/PhpSpreadsheet/Worksheet/Table/Column.php @@ -216,7 +216,7 @@ class Column foreach ($worksheet->getCoordinates(false) as $coordinate) { $cell = $worksheet->getCell($coordinate); if ($cell->getDataType() === DataType::TYPE_FORMULA) { - $formula = $cell->getValue(); + $formula = $cell->getValueString(); if (preg_match($pattern, $formula) === 1) { $formula = preg_replace($pattern, "[$1{$newTitle}]", $formula); $cell->setValueExplicit($formula, DataType::TYPE_FORMULA); diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index ccf305b48..91885c55b 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -2860,7 +2860,7 @@ class Worksheet implements IComparable * @param bool $ignoreHidden False - Return values for rows/columns even if they are defined as hidden. * True - Don't return values for rows/columns that are defined as hidden. * - * @return Generator + * @return Generator */ public function rangeToArrayYieldRows( string $range, diff --git a/src/PhpSpreadsheet/Writer/Csv.php b/src/PhpSpreadsheet/Writer/Csv.php index eadfc27bd..6ce968d8c 100644 --- a/src/PhpSpreadsheet/Writer/Csv.php +++ b/src/PhpSpreadsheet/Writer/Csv.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Writer; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use Stringable; class Csv extends BaseWriter { @@ -246,6 +247,8 @@ class Csv extends BaseWriter /** * Convert boolean to TRUE/FALSE; otherwise return element cast to string. + * + * @param null|bool|float|int|string|Stringable $element element to be converted */ private static function elementToString(mixed $element): string { @@ -270,6 +273,7 @@ class Csv extends BaseWriter // Build the line $line = ''; + /** @var null|bool|float|int|string|Stringable $element */ foreach ($values as $element) { $element = self::elementToString($element); // Add delimiter diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index f395e5ea0..db6db3038 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -1310,10 +1310,11 @@ class Html extends BaseWriter $cellData .= $this->generateRowCellDataValueRich($cell->getValue()); } else { $origData = $this->preCalculateFormulas ? $cell->getCalculatedValue() : $cell->getValue(); + $origData2 = $this->preCalculateFormulas ? $cell->getCalculatedValueString() : $cell->getValueString(); $formatCode = $worksheet->getParentOrThrow()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode(); $cellData = NumberFormat::toFormattedString( - $origData ?? '', + $origData2, $formatCode ?? NumberFormat::FORMAT_GENERAL, [$this, 'formatColor'] ); diff --git a/src/PhpSpreadsheet/Writer/Ods/Content.php b/src/PhpSpreadsheet/Writer/Ods/Content.php index cfa1dd1b4..7b052bbcc 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Content.php +++ b/src/PhpSpreadsheet/Writer/Ods/Content.php @@ -209,8 +209,8 @@ class Content extends WriterPart switch ($cell->getDataType()) { case DataType::TYPE_BOOL: $objWriter->writeAttribute('office:value-type', 'boolean'); - $objWriter->writeAttribute('office:value', $cell->getValue()); - $objWriter->writeElement('text:p', $cell->getValue()); + $objWriter->writeAttribute('office:value', $cell->getValueString()); + $objWriter->writeElement('text:p', $cell->getValueString()); break; case DataType::TYPE_ERROR: @@ -221,15 +221,15 @@ class Content extends WriterPart break; case DataType::TYPE_FORMULA: - $formulaValue = $cell->getValue(); + $formulaValue = $cell->getValueString(); if ($this->getParentWriter()->getPreCalculateFormulas()) { try { - $formulaValue = $cell->getCalculatedValue(); + $formulaValue = $cell->getCalculatedValueString(); } catch (CalculationException $e) { // don't do anything } } - $objWriter->writeAttribute('table:formula', $this->formulaConvertor->convertFormula($cell->getValue())); + $objWriter->writeAttribute('table:formula', $this->formulaConvertor->convertFormula($cell->getValueString())); if (is_numeric($formulaValue)) { $objWriter->writeAttribute('office:value-type', 'float'); } else { @@ -241,8 +241,8 @@ class Content extends WriterPart break; case DataType::TYPE_NUMERIC: $objWriter->writeAttribute('office:value-type', 'float'); - $objWriter->writeAttribute('office:value', $cell->getValue()); - $objWriter->writeElement('text:p', $cell->getValue()); + $objWriter->writeAttribute('office:value', $cell->getValueString()); + $objWriter->writeElement('text:p', $cell->getValueString()); break; case DataType::TYPE_INLINE: @@ -251,7 +251,7 @@ class Content extends WriterPart $objWriter->writeAttribute('office:value-type', 'string'); $url = $cell->getHyperlink()->getUrl(); if (empty($url)) { - $objWriter->writeElement('text:p', $cell->getValue()); + $objWriter->writeElement('text:p', $cell->getValueString()); } else { $objWriter->startElement('text:p'); $objWriter->startElement('text:a'); @@ -262,7 +262,7 @@ class Content extends WriterPart } $objWriter->writeAttribute('xlink:href', $url); $objWriter->writeAttribute('xlink:type', 'simple'); - $objWriter->text($cell->getValue()); + $objWriter->text($cell->getValueString()); $objWriter->endElement(); // text:a $objWriter->endElement(); // text:p } diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Table.php b/src/PhpSpreadsheet/Writer/Xlsx/Table.php index 5b0b22bca..4e6ceec84 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Table.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Table.php @@ -80,7 +80,7 @@ class Table extends WriterPart $objWriter->startElement('tableColumn'); $objWriter->writeAttribute('id', (string) ($offset + 1)); - $objWriter->writeAttribute('name', $table->getShowHeaderRow() ? $cell->getValue() : 'Column' . ($offset + 1)); + $objWriter->writeAttribute('name', $table->getShowHeaderRow() ? $cell->getValueString() : ('Column' . ($offset + 1))); if ($table->getShowTotalsRow()) { if ($column->getTotalsRowLabel()) { diff --git a/tests/PhpSpreadsheetTests/Cell/CellAddressTest.php b/tests/PhpSpreadsheetTests/Cell/CellAddressTest.php index 39d85392c..3cb204b3f 100644 --- a/tests/PhpSpreadsheetTests/Cell/CellAddressTest.php +++ b/tests/PhpSpreadsheetTests/Cell/CellAddressTest.php @@ -84,7 +84,7 @@ class CellAddressTest extends TestCase /** * @dataProvider providerCreateFromColumnRowException */ - public function testCreateFromColumnRowException(mixed $columnId, mixed $rowId): void + public function testCreateFromColumnRowException(int|string $columnId, int|string $rowId): void { $this->expectException(Exception::class); $this->expectExceptionMessage('Row and Column Ids must be positive integer values'); diff --git a/tests/PhpSpreadsheetTests/Document/PropertiesTest.php b/tests/PhpSpreadsheetTests/Document/PropertiesTest.php index b81edc824..7d491d25e 100644 --- a/tests/PhpSpreadsheetTests/Document/PropertiesTest.php +++ b/tests/PhpSpreadsheetTests/Document/PropertiesTest.php @@ -153,7 +153,7 @@ class PropertiesTest extends TestCase /** * @dataProvider providerCustomProperties */ - public function testSetCustomProperties(mixed $expectedType, mixed $expectedValue, string $propertyName, mixed $propertyValue, ?string $propertyType = null): void + public function testSetCustomProperties(mixed $expectedType, mixed $expectedValue, string $propertyName, null|bool|float|int|string $propertyValue, ?string $propertyType = null): void { if ($propertyType === null) { $this->properties->setCustomProperty($propertyName, $propertyValue); diff --git a/tests/PhpSpreadsheetTests/Style/NumberFormatTest.php b/tests/PhpSpreadsheetTests/Style/NumberFormatTest.php index 0a1aaf292..0c2b4748a 100644 --- a/tests/PhpSpreadsheetTests/Style/NumberFormatTest.php +++ b/tests/PhpSpreadsheetTests/Style/NumberFormatTest.php @@ -26,6 +26,8 @@ class NumberFormatTest extends TestCase /** * @dataProvider providerNumberFormat + * + * @param null|bool|float|int|string $args string to be formatted */ public function testFormatValueWithMask(mixed $expectedResult, mixed ...$args): void { @@ -40,6 +42,8 @@ class NumberFormatTest extends TestCase /** * @dataProvider providerNumberFormatFractions + * + * @param null|bool|float|int|string $args string to be formatted */ public function testFormatValueWithMaskFraction(mixed $expectedResult, mixed ...$args): void { @@ -54,6 +58,8 @@ class NumberFormatTest extends TestCase /** * @dataProvider providerNumberFormatDates + * + * @param null|bool|float|int|string $args string to be formatted */ public function testFormatValueWithMaskDate(mixed $expectedResult, mixed ...$args): void { From 8d5577a3c4143227b822d30013335e18d2559b93 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sun, 5 May 2024 06:14:28 -0700 Subject: [PATCH 2/2] Improved Test for ConvertUOM Scrutinizer balked at quotes around key 'Unit Name'; no reason not to use 'UnitName' instead. Having done that, several ConvertUOM tests seemed a little unconvincing. Replaced them with improved versions. --- .../Calculation/Engineering/ConvertUOM.php | 310 +++++++++--------- .../Functions/Engineering/ConvertUoMTest.php | 16 +- 2 files changed, 166 insertions(+), 160 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php index 5fc32badb..969c270ad 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php @@ -27,175 +27,175 @@ class ConvertUOM /** * Details of the Units of measure that can be used in CONVERTUOM(). * - * @var array + * @var array */ private static array $conversionUnits = [ // Weight and Mass - 'g' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Gram', 'AllowPrefix' => true], - 'sg' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Slug', 'AllowPrefix' => false], - 'lbm' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Pound mass (avoirdupois)', 'AllowPrefix' => false], - 'u' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'U (atomic mass unit)', 'AllowPrefix' => true], - 'ozm' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => false], - 'grain' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Grain', 'AllowPrefix' => false], - 'cwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'U.S. (short) hundredweight', 'AllowPrefix' => false], - 'shweight' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'U.S. (short) hundredweight', 'AllowPrefix' => false], - 'uk_cwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial hundredweight', 'AllowPrefix' => false], - 'lcwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial hundredweight', 'AllowPrefix' => false], - 'hweight' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial hundredweight', 'AllowPrefix' => false], - 'stone' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Stone', 'AllowPrefix' => false], - 'ton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Ton', 'AllowPrefix' => false], - 'uk_ton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial ton', 'AllowPrefix' => false], - 'LTON' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial ton', 'AllowPrefix' => false], - 'brton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial ton', 'AllowPrefix' => false], + 'g' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Gram', 'AllowPrefix' => true], + 'sg' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Slug', 'AllowPrefix' => false], + 'lbm' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Pound mass (avoirdupois)', 'AllowPrefix' => false], + 'u' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'U (atomic mass unit)', 'AllowPrefix' => true], + 'ozm' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => false], + 'grain' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Grain', 'AllowPrefix' => false], + 'cwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'U.S. (short) hundredweight', 'AllowPrefix' => false], + 'shweight' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'U.S. (short) hundredweight', 'AllowPrefix' => false], + 'uk_cwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial hundredweight', 'AllowPrefix' => false], + 'lcwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial hundredweight', 'AllowPrefix' => false], + 'hweight' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial hundredweight', 'AllowPrefix' => false], + 'stone' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Stone', 'AllowPrefix' => false], + 'ton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Ton', 'AllowPrefix' => false], + 'uk_ton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial ton', 'AllowPrefix' => false], + 'LTON' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial ton', 'AllowPrefix' => false], + 'brton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial ton', 'AllowPrefix' => false], // Distance - 'm' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Meter', 'AllowPrefix' => true], - 'mi' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Statute mile', 'AllowPrefix' => false], - 'Nmi' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Nautical mile', 'AllowPrefix' => false], - 'in' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Inch', 'AllowPrefix' => false], - 'ft' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Foot', 'AllowPrefix' => false], - 'yd' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Yard', 'AllowPrefix' => false], - 'ang' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Angstrom', 'AllowPrefix' => true], - 'ell' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Ell', 'AllowPrefix' => false], - 'ly' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Light Year', 'AllowPrefix' => false], - 'parsec' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Parsec', 'AllowPrefix' => false], - 'pc' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Parsec', 'AllowPrefix' => false], - 'Pica' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => false], - 'Picapt' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => false], - 'pica' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Pica (1/6 in)', 'AllowPrefix' => false], - 'survey_mi' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'U.S survey mile (statute mile)', 'AllowPrefix' => false], + 'm' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Meter', 'AllowPrefix' => true], + 'mi' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Statute mile', 'AllowPrefix' => false], + 'Nmi' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Nautical mile', 'AllowPrefix' => false], + 'in' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Inch', 'AllowPrefix' => false], + 'ft' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Foot', 'AllowPrefix' => false], + 'yd' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Yard', 'AllowPrefix' => false], + 'ang' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Angstrom', 'AllowPrefix' => true], + 'ell' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Ell', 'AllowPrefix' => false], + 'ly' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Light Year', 'AllowPrefix' => false], + 'parsec' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Parsec', 'AllowPrefix' => false], + 'pc' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Parsec', 'AllowPrefix' => false], + 'Pica' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Pica (1/72 in)', 'AllowPrefix' => false], + 'Picapt' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Pica (1/72 in)', 'AllowPrefix' => false], + 'pica' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Pica (1/6 in)', 'AllowPrefix' => false], + 'survey_mi' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'U.S survey mile (statute mile)', 'AllowPrefix' => false], // Time - 'yr' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Year', 'AllowPrefix' => false], - 'day' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Day', 'AllowPrefix' => false], - 'd' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Day', 'AllowPrefix' => false], - 'hr' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Hour', 'AllowPrefix' => false], - 'mn' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Minute', 'AllowPrefix' => false], - 'min' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Minute', 'AllowPrefix' => false], - 'sec' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Second', 'AllowPrefix' => true], - 's' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Second', 'AllowPrefix' => true], + 'yr' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Year', 'AllowPrefix' => false], + 'day' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Day', 'AllowPrefix' => false], + 'd' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Day', 'AllowPrefix' => false], + 'hr' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Hour', 'AllowPrefix' => false], + 'mn' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Minute', 'AllowPrefix' => false], + 'min' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Minute', 'AllowPrefix' => false], + 'sec' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Second', 'AllowPrefix' => true], + 's' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Second', 'AllowPrefix' => true], // Pressure - 'Pa' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Pascal', 'AllowPrefix' => true], - 'p' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Pascal', 'AllowPrefix' => true], - 'atm' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true], - 'at' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true], - 'mmHg' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'mm of Mercury', 'AllowPrefix' => true], - 'psi' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'PSI', 'AllowPrefix' => true], - 'Torr' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Torr', 'AllowPrefix' => true], + 'Pa' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Pascal', 'AllowPrefix' => true], + 'p' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Pascal', 'AllowPrefix' => true], + 'atm' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Atmosphere', 'AllowPrefix' => true], + 'at' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Atmosphere', 'AllowPrefix' => true], + 'mmHg' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'mm of Mercury', 'AllowPrefix' => true], + 'psi' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'PSI', 'AllowPrefix' => true], + 'Torr' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Torr', 'AllowPrefix' => true], // Force - 'N' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Newton', 'AllowPrefix' => true], - 'dyn' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Dyne', 'AllowPrefix' => true], - 'dy' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Dyne', 'AllowPrefix' => true], - 'lbf' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Pound force', 'AllowPrefix' => false], - 'pond' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Pond', 'AllowPrefix' => true], + 'N' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Newton', 'AllowPrefix' => true], + 'dyn' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Dyne', 'AllowPrefix' => true], + 'dy' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Dyne', 'AllowPrefix' => true], + 'lbf' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Pound force', 'AllowPrefix' => false], + 'pond' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Pond', 'AllowPrefix' => true], // Energy - 'J' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Joule', 'AllowPrefix' => true], - 'e' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Erg', 'AllowPrefix' => true], - 'c' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Thermodynamic calorie', 'AllowPrefix' => true], - 'cal' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'IT calorie', 'AllowPrefix' => true], - 'eV' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Electron volt', 'AllowPrefix' => true], - 'ev' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Electron volt', 'AllowPrefix' => true], - 'HPh' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false], - 'hh' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false], - 'Wh' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true], - 'wh' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true], - 'flb' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Foot-pound', 'AllowPrefix' => false], - 'BTU' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'BTU', 'AllowPrefix' => false], - 'btu' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'BTU', 'AllowPrefix' => false], + 'J' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Joule', 'AllowPrefix' => true], + 'e' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Erg', 'AllowPrefix' => true], + 'c' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Thermodynamic calorie', 'AllowPrefix' => true], + 'cal' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'IT calorie', 'AllowPrefix' => true], + 'eV' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Electron volt', 'AllowPrefix' => true], + 'ev' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Electron volt', 'AllowPrefix' => true], + 'HPh' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Horsepower-hour', 'AllowPrefix' => false], + 'hh' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Horsepower-hour', 'AllowPrefix' => false], + 'Wh' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Watt-hour', 'AllowPrefix' => true], + 'wh' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Watt-hour', 'AllowPrefix' => true], + 'flb' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Foot-pound', 'AllowPrefix' => false], + 'BTU' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'BTU', 'AllowPrefix' => false], + 'btu' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'BTU', 'AllowPrefix' => false], // Power - 'HP' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Horsepower', 'AllowPrefix' => false], - 'h' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Horsepower', 'AllowPrefix' => false], - 'W' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Watt', 'AllowPrefix' => true], - 'w' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Watt', 'AllowPrefix' => true], - 'PS' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Pferdestärke', 'AllowPrefix' => false], + 'HP' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Horsepower', 'AllowPrefix' => false], + 'h' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Horsepower', 'AllowPrefix' => false], + 'W' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Watt', 'AllowPrefix' => true], + 'w' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Watt', 'AllowPrefix' => true], + 'PS' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Pferdestärke', 'AllowPrefix' => false], // Magnetism - 'T' => ['Group' => self::CATEGORY_MAGNETISM, 'Unit Name' => 'Tesla', 'AllowPrefix' => true], - 'ga' => ['Group' => self::CATEGORY_MAGNETISM, 'Unit Name' => 'Gauss', 'AllowPrefix' => true], + 'T' => ['Group' => self::CATEGORY_MAGNETISM, 'UnitName' => 'Tesla', 'AllowPrefix' => true], + 'ga' => ['Group' => self::CATEGORY_MAGNETISM, 'UnitName' => 'Gauss', 'AllowPrefix' => true], // Temperature - 'C' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Celsius', 'AllowPrefix' => false], - 'cel' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Celsius', 'AllowPrefix' => false], - 'F' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Fahrenheit', 'AllowPrefix' => false], - 'fah' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Fahrenheit', 'AllowPrefix' => false], - 'K' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Kelvin', 'AllowPrefix' => false], - 'kel' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Kelvin', 'AllowPrefix' => false], - 'Rank' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Rankine', 'AllowPrefix' => false], - 'Reau' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Réaumur', 'AllowPrefix' => false], + 'C' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Celsius', 'AllowPrefix' => false], + 'cel' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Celsius', 'AllowPrefix' => false], + 'F' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Fahrenheit', 'AllowPrefix' => false], + 'fah' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Fahrenheit', 'AllowPrefix' => false], + 'K' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Kelvin', 'AllowPrefix' => false], + 'kel' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Kelvin', 'AllowPrefix' => false], + 'Rank' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Rankine', 'AllowPrefix' => false], + 'Reau' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Réaumur', 'AllowPrefix' => false], // Volume - 'l' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Litre', 'AllowPrefix' => true], - 'L' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Litre', 'AllowPrefix' => true], - 'lt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Litre', 'AllowPrefix' => true], - 'tsp' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Teaspoon', 'AllowPrefix' => false], - 'tspm' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Modern Teaspoon', 'AllowPrefix' => false], - 'tbs' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Tablespoon', 'AllowPrefix' => false], - 'oz' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Fluid Ounce', 'AllowPrefix' => false], - 'cup' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cup', 'AllowPrefix' => false], - 'pt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false], - 'us_pt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false], - 'uk_pt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'U.K. Pint', 'AllowPrefix' => false], - 'qt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Quart', 'AllowPrefix' => false], - 'uk_qt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Imperial Quart (UK)', 'AllowPrefix' => false], - 'gal' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Gallon', 'AllowPrefix' => false], - 'uk_gal' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Imperial Gallon (UK)', 'AllowPrefix' => false], - 'ang3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Angstrom', 'AllowPrefix' => true], - 'ang^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Angstrom', 'AllowPrefix' => true], - 'barrel' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'US Oil Barrel', 'AllowPrefix' => false], - 'bushel' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'US Bushel', 'AllowPrefix' => false], - 'in3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Inch', 'AllowPrefix' => false], - 'in^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Inch', 'AllowPrefix' => false], - 'ft3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Foot', 'AllowPrefix' => false], - 'ft^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Foot', 'AllowPrefix' => false], - 'ly3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Light Year', 'AllowPrefix' => false], - 'ly^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Light Year', 'AllowPrefix' => false], - 'm3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Meter', 'AllowPrefix' => true], - 'm^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Meter', 'AllowPrefix' => true], - 'mi3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Mile', 'AllowPrefix' => false], - 'mi^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Mile', 'AllowPrefix' => false], - 'yd3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Yard', 'AllowPrefix' => false], - 'yd^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Yard', 'AllowPrefix' => false], - 'Nmi3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Nautical Mile', 'AllowPrefix' => false], - 'Nmi^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Nautical Mile', 'AllowPrefix' => false], - 'Pica3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Pica', 'AllowPrefix' => false], - 'Pica^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Pica', 'AllowPrefix' => false], - 'Picapt3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Pica', 'AllowPrefix' => false], - 'Picapt^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Pica', 'AllowPrefix' => false], - 'GRT' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Gross Registered Ton', 'AllowPrefix' => false], - 'regton' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Gross Registered Ton', 'AllowPrefix' => false], - 'MTON' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Measurement Ton (Freight Ton)', 'AllowPrefix' => false], + 'l' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Litre', 'AllowPrefix' => true], + 'L' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Litre', 'AllowPrefix' => true], + 'lt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Litre', 'AllowPrefix' => true], + 'tsp' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Teaspoon', 'AllowPrefix' => false], + 'tspm' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Modern Teaspoon', 'AllowPrefix' => false], + 'tbs' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Tablespoon', 'AllowPrefix' => false], + 'oz' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Fluid Ounce', 'AllowPrefix' => false], + 'cup' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cup', 'AllowPrefix' => false], + 'pt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'U.S. Pint', 'AllowPrefix' => false], + 'us_pt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'U.S. Pint', 'AllowPrefix' => false], + 'uk_pt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'U.K. Pint', 'AllowPrefix' => false], + 'qt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Quart', 'AllowPrefix' => false], + 'uk_qt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Imperial Quart (UK)', 'AllowPrefix' => false], + 'gal' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Gallon', 'AllowPrefix' => false], + 'uk_gal' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Imperial Gallon (UK)', 'AllowPrefix' => false], + 'ang3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Angstrom', 'AllowPrefix' => true], + 'ang^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Angstrom', 'AllowPrefix' => true], + 'barrel' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'US Oil Barrel', 'AllowPrefix' => false], + 'bushel' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'US Bushel', 'AllowPrefix' => false], + 'in3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Inch', 'AllowPrefix' => false], + 'in^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Inch', 'AllowPrefix' => false], + 'ft3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Foot', 'AllowPrefix' => false], + 'ft^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Foot', 'AllowPrefix' => false], + 'ly3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Light Year', 'AllowPrefix' => false], + 'ly^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Light Year', 'AllowPrefix' => false], + 'm3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Meter', 'AllowPrefix' => true], + 'm^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Meter', 'AllowPrefix' => true], + 'mi3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Mile', 'AllowPrefix' => false], + 'mi^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Mile', 'AllowPrefix' => false], + 'yd3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Yard', 'AllowPrefix' => false], + 'yd^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Yard', 'AllowPrefix' => false], + 'Nmi3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Nautical Mile', 'AllowPrefix' => false], + 'Nmi^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Nautical Mile', 'AllowPrefix' => false], + 'Pica3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Pica', 'AllowPrefix' => false], + 'Pica^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Pica', 'AllowPrefix' => false], + 'Picapt3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Pica', 'AllowPrefix' => false], + 'Picapt^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Pica', 'AllowPrefix' => false], + 'GRT' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Gross Registered Ton', 'AllowPrefix' => false], + 'regton' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Gross Registered Ton', 'AllowPrefix' => false], + 'MTON' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Measurement Ton (Freight Ton)', 'AllowPrefix' => false], // Area - 'ha' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Hectare', 'AllowPrefix' => true], - 'uk_acre' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'International Acre', 'AllowPrefix' => false], - 'us_acre' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'US Survey/Statute Acre', 'AllowPrefix' => false], - 'ang2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Angstrom', 'AllowPrefix' => true], - 'ang^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Angstrom', 'AllowPrefix' => true], - 'ar' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Are', 'AllowPrefix' => true], - 'ft2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Feet', 'AllowPrefix' => false], - 'ft^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Feet', 'AllowPrefix' => false], - 'in2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Inches', 'AllowPrefix' => false], - 'in^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Inches', 'AllowPrefix' => false], - 'ly2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Light Years', 'AllowPrefix' => false], - 'ly^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Light Years', 'AllowPrefix' => false], - 'm2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Meters', 'AllowPrefix' => true], - 'm^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Meters', 'AllowPrefix' => true], - 'Morgen' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Morgen', 'AllowPrefix' => false], - 'mi2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Miles', 'AllowPrefix' => false], - 'mi^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Miles', 'AllowPrefix' => false], - 'Nmi2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Nautical Miles', 'AllowPrefix' => false], - 'Nmi^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Nautical Miles', 'AllowPrefix' => false], - 'Pica2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Pica', 'AllowPrefix' => false], - 'Pica^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Pica', 'AllowPrefix' => false], - 'Picapt2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Pica', 'AllowPrefix' => false], - 'Picapt^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Pica', 'AllowPrefix' => false], - 'yd2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Yards', 'AllowPrefix' => false], - 'yd^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Yards', 'AllowPrefix' => false], + 'ha' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Hectare', 'AllowPrefix' => true], + 'uk_acre' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'International Acre', 'AllowPrefix' => false], + 'us_acre' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'US Survey/Statute Acre', 'AllowPrefix' => false], + 'ang2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Angstrom', 'AllowPrefix' => true], + 'ang^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Angstrom', 'AllowPrefix' => true], + 'ar' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Are', 'AllowPrefix' => true], + 'ft2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Feet', 'AllowPrefix' => false], + 'ft^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Feet', 'AllowPrefix' => false], + 'in2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Inches', 'AllowPrefix' => false], + 'in^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Inches', 'AllowPrefix' => false], + 'ly2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Light Years', 'AllowPrefix' => false], + 'ly^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Light Years', 'AllowPrefix' => false], + 'm2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Meters', 'AllowPrefix' => true], + 'm^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Meters', 'AllowPrefix' => true], + 'Morgen' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Morgen', 'AllowPrefix' => false], + 'mi2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Miles', 'AllowPrefix' => false], + 'mi^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Miles', 'AllowPrefix' => false], + 'Nmi2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Nautical Miles', 'AllowPrefix' => false], + 'Nmi^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Nautical Miles', 'AllowPrefix' => false], + 'Pica2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Pica', 'AllowPrefix' => false], + 'Pica^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Pica', 'AllowPrefix' => false], + 'Picapt2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Pica', 'AllowPrefix' => false], + 'Picapt^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Pica', 'AllowPrefix' => false], + 'yd2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Yards', 'AllowPrefix' => false], + 'yd^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Yards', 'AllowPrefix' => false], // Information - 'byte' => ['Group' => self::CATEGORY_INFORMATION, 'Unit Name' => 'Byte', 'AllowPrefix' => true], - 'bit' => ['Group' => self::CATEGORY_INFORMATION, 'Unit Name' => 'Bit', 'AllowPrefix' => true], + 'byte' => ['Group' => self::CATEGORY_INFORMATION, 'UnitName' => 'Byte', 'AllowPrefix' => true], + 'bit' => ['Group' => self::CATEGORY_INFORMATION, 'UnitName' => 'Bit', 'AllowPrefix' => true], // Speed - 'm/s' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Meters per second', 'AllowPrefix' => true], - 'm/sec' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Meters per second', 'AllowPrefix' => true], - 'm/h' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Meters per hour', 'AllowPrefix' => true], - 'm/hr' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Meters per hour', 'AllowPrefix' => true], - 'mph' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Miles per hour', 'AllowPrefix' => false], - 'admkn' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Admiralty Knot', 'AllowPrefix' => false], - 'kn' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Knot', 'AllowPrefix' => false], + 'm/s' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Meters per second', 'AllowPrefix' => true], + 'm/sec' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Meters per second', 'AllowPrefix' => true], + 'm/h' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Meters per hour', 'AllowPrefix' => true], + 'm/hr' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Meters per hour', 'AllowPrefix' => true], + 'mph' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Miles per hour', 'AllowPrefix' => false], + 'admkn' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Admiralty Knot', 'AllowPrefix' => false], + 'kn' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Knot', 'AllowPrefix' => false], ]; /** @@ -476,7 +476,7 @@ class ConvertUOM if (($category === null) || ($conversionGroup['Group'] == $category)) { $conversionGroups[$conversionGroup['Group']][] = [ 'unit' => $conversionUnit, - 'description' => $conversionGroup['Unit Name'], + 'description' => $conversionGroup['UnitName'], ]; } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php index a41e23f78..e8044792a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php @@ -18,31 +18,37 @@ class ConvertUoMTest extends TestCase public function testGetConversionGroups(): void { $result = ConvertUOM::getConversionCategories(); - self::assertIsArray($result); + self::assertContains('Weight and Mass', $result); } public function testGetConversionGroupUnits(): void { $result = ConvertUOM::getConversionCategoryUnits(); - self::assertIsArray($result); + self::assertArrayHasKey('Speed', $result); + self::assertIsArray($result['Speed']); + self::assertContains('mph', $result['Speed']); } public function testGetConversionGroupUnitDetails(): void { $result = ConvertUOM::getConversionCategoryUnitDetails(); - self::assertIsArray($result); + self::assertArrayHasKey('Information', $result); + self::assertIsArray($result['Information']); + self::assertContains(['unit' => 'byte', 'description' => 'Byte'], $result['Information']); } public function testGetConversionMultipliers(): void { $result = ConvertUOM::getConversionMultipliers(); - self::assertIsArray($result); + self::assertArrayHasKey('k', $result); + self::assertSame(['multiplier' => 1000.0, 'name' => 'kilo'], $result['k']); } public function testGetBinaryConversionMultipliers(): void { $result = ConvertUOM::getBinaryConversionMultipliers(); - self::assertIsArray($result); + self::assertArrayHasKey('ki', $result); + self::assertSame(['multiplier' => 1024, 'name' => 'kibi'], $result['ki']); } /**