Currency and Accounting Formats

Fix #4125. Currency and Accounting Wizards generate styles for ISO codes, but these are incorrect and cause a problem when Excel tries to open a spreadsheet containing these styles. Debugging that problem, other problems with Wizards came to light:
- Currency Wizard should permit four different styles for negative numbers (as Excel does) - minus sign, minus sign and red font, paretheses, and parenthese and red font. It currently uses only minus sign.
- Accounting Wizard should use parentheses for negative numbers (as Excel does). It currently uses minus sign.
- Accounting Wizard should always use SYMBOL_WITH_SPACING (as Excel does). It currently permits the use of SYMBOL_WITHOUT_SPACING. What WITH_SPACING really does is to ensure decimal-point alignment among adjacent cells in a column with the same format.
- Currency Wizard should always use SYMBOL_WITHOUT_SPACING (as Excel does). It currently permits the use of SYMBOL_WITH_SPACING.

I am correcting these problems by:
- renaming Currency Wizard to CurrencyBase
- adding a `negative` property with setter to it and its constructor.
- adding a new Currency which extends CurrencyBase, always using SYMBOL_WITHOUT_SPACING when formatting.
- having Accounting extend CurrencyBase rather than Currency, always using SYMBOL_WITH_SPACING and NEGATIVE_PARENS when formatting.
- CurrencyBase can be used if the restrictions on Currency and Accounting are not desired (e.g. the suggested accounting constant from [this unimplemented PR](https://github.com/PHPOffice/PhpSpreadsheet/pull/1576)).

Excel does some funny stuff with these formats. In particular, it might try to guess if you have a particular Accounting format in mind. So the Accounting wizard for dollar sign generates a format which (a) matches FORMAT_ACCOUNTING_USD, and (b) Excel (correctly) interprets as an Accounting format for symbol $. On the other hand, the Accounting wizard for euro sign generates a format which (a) matches FORMAT_ACCOUNTING_EUR, but (b) Excel interprets as a custom code rather than an Accounting format. This in itself is not a particularly big deal, but it has made it impossible for me to see exactly what format Excel uses for trailing currency symbols for negative numbers. I can't get them to decimal-point align with positive numbers if I put any kind of space between the trailing parenthesis and the currency symbol, so I omit that. It doesn't look terrible, and it keeps everything aligned, but it might not be what people are used to.

I've also changed the formatting to use spaces rather than non-breaking spaces. They seem to work just fine, and the constants mentioned above use them rather than nbsp.

Fix #4124. Currency formats that contain an ISO currency code which contains one of the characters used to recognize a date format (hmsdy), e.g. [$HUF], are being formatted by PhpSpreadsheet as dates rather than currencies. Code is changed to recognize open bracket followed by dollar sign followed by 3 Latin alphabetic characters followed by close bracket as a non-date.
This commit is contained in:
oleibman
2024-08-05 18:36:06 -07:00
parent 3b150557ad
commit ee1d4d0367
11 changed files with 831 additions and 194 deletions
+469
View File
@@ -0,0 +1,469 @@
<?php
require __DIR__ . '/../Header.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Accounting;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Currency;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\CurrencyBase;
$spreadsheet = new Spreadsheet();
$helper->log('First sheet - Accounting Wizard');
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle('Accounting');
$sheet->getCell('A1')->setValue('Currency');
$sheet->getCell('B1')->setValue('Decimals');
$sheet->getCell('C1')->setValue('ThouSep');
$sheet->getCell('D1')->setValue('Lead');
$sheet->getCell('E1')->setValue('Spacing');
$sheet->getCell('F1')->setValue('Neg');
$sheet->getCell('G1')->setValue('Pos');
$sheet->getCell('H1')->setValue('Zero');
$sheet->getCell('I1')->setValue('Neg');
$sheet->getCell('J1')->setValue('Text');
$sheet->getCell('L1')->setValue('ActWiz$');
$sheet->getCell('M1')->setValue('ActWiz€Trl');
$sheet->freezePane('A2');
$sheet->getComment('E1')->getText()->createText('ignored, always true for Accounting');
$sheet->getComment('F1')->getText()->createText('ignored, always () for Accounting');
$sheet->getCell('A2')->setValue('AcctUSD');
$sheet->getCell('G2')->setValue(1234.56);
$sheet->getCell('H2')->setValue(0);
$sheet->getCell('I2')->setValue(-1234.56);
$sheet->getCell('J2')->setValue('text');
$sheet->getStyle('G2:J2')->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_ACCOUNTING_USD);
$sheet->getCell('A3')->setValue('AcctEur');
$sheet->getCell('G3')->setValue(1234.56);
$sheet->getCell('H3')->setValue(0);
$sheet->getCell('I3')->setValue(-1234.56);
$sheet->getCell('J3')->setValue('Text');
$sheet->getStyle('G3:J3')->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_ACCOUNTING_EUR);
$sheet->getCell('A4')->setValue('AcctWiz¥');
$sheet->getCell('E4')->setValue(true);
$sheet->getCell('G4')->setValue(1234.56);
$sheet->getCell('H4')->setValue(0);
$sheet->getCell('I4')->setValue(-1234.56);
$sheet->getCell('J4')->setValue('Text');
$sheet->getStyle('G4:J4')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Accounting('¥', currencySymbolSpacing: true))->format(),
],
]
);
$sheet->getCell('A5')->setValue('StalePR¥');
$sheet->getCell('G5')->setValue(1234.56);
$sheet->getCell('H5')->setValue(0);
$sheet->getCell('I5')->setValue(-1234.56);
$sheet->getCell('J5')->setValue('Text');
$sheet->getStyle('G5:J5')->getNumberFormat()->setFormatCode('_("¥"* #,##0.00_);_("¥"* -#,##0.00_);_("¥"* "-"??_);_(@_)');
$sheet->getCell('A6')->setValue('AcctWiz¥');
$sheet->getCell('E6')->setValue(true);
$sheet->getCell('F6')->setValue(Currency::NEGATIVE_MINUS);
$sheet->getCell('G6')->setValue(1234.56);
$sheet->getCell('H6')->setValue(0);
$sheet->getCell('I6')->setValue(-1234.56);
$sheet->getCell('J6')->setValue('Text');
$sheet->getStyle('G6:J6')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Accounting('¥', currencySymbolSpacing: true, negative: Currency::NEGATIVE_MINUS))->format(),
],
]
);
$sheet->getCell('A7')->setValue('AcctWiz¥');
$sheet->getCell('E7')->setValue(false);
$sheet->getCell('F7')->setValue(Currency::NEGATIVE_MINUS);
$sheet->getCell('G7')->setValue(1234.56);
$sheet->getCell('H7')->setValue(0);
$sheet->getCell('I7')->setValue(-1234.56);
$sheet->getCell('J7')->setValue('Text');
$sheet->getStyle('G7:J7')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Accounting('¥', currencySymbolSpacing: false, negative: Currency::NEGATIVE_MINUS))->format(),
],
]
);
$sheet->getCell('A8')->setValue('AcctWiz¥');
$sheet->getCell('E8')->setValue(false);
$sheet->getCell('F8')->setValue(Currency::NEGATIVE_PARENS);
$sheet->getCell('G8')->setValue(1234.56);
$sheet->getCell('H8')->setValue(0);
$sheet->getCell('I8')->setValue(-1234.56);
$sheet->getCell('J8')->setValue('Text');
$sheet->getStyle('G8:J8')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Accounting('¥', currencySymbolSpacing: false, negative: Currency::NEGATIVE_PARENS))->format(),
],
]
);
$sheet->getCell('A9')->setValue('AcctW HUF');
$sheet->getCell('E9')->setValue(true);
$sheet->getCell('G9')->setValue(1234.56);
$sheet->getCell('H9')->setValue(0);
$sheet->getCell('I9')->setValue(-1234.56);
$sheet->getCell('J9')->setValue('Text');
$sheet->getStyle('G9:J9')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Accounting('HUF', currencySymbolSpacing: true))->format(),
],
]
);
$sheet->getCell('A10')->setValue('AcctW HUF');
$sheet->getCell('E10')->setValue(true);
$sheet->getCell('F10')->setValue(Currency::NEGATIVE_RED_PARENS);
$sheet->getCell('G10')->setValue(1234.56);
$sheet->getCell('H10')->setValue(0);
$sheet->getCell('I10')->setValue(-1234.56);
$sheet->getCell('J10')->setValue('Text');
$sheet->getStyle('G10:J10')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Accounting('HUF', currencySymbolSpacing: true, negative: Currency::NEGATIVE_RED_PARENS))->format(),
],
]
);
$sheet->getCell('A11')->setValue('AcctW Kazakh');
$sheet->getCell('D11')->setValue(false);
$sheet->getCell('G11')->setValue(1234.56);
$sheet->getCell('H11')->setValue(0);
$sheet->getCell('I11')->setValue(-1234.56);
$sheet->getCell('J11')->setValue('Text');
$sheet->getStyle('G11:J11')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Accounting('₸', currencySymbolPosition: Accounting::TRAILING_SYMBOL))->format(),
],
]
);
$sheet->getCell('A12')->setValue('AcctW $');
$sheet->getCell('B12')->setValue(3);
$sheet->getCell('C12')->setValue(false);
$sheet->getCell('D12')->setValue(false);
$sheet->getCell('F12')->setValue(Currency::NEGATIVE_RED_MINUS);
$sheet->getCell('G12')->setValue(1234.56);
$sheet->getCell('H12')->setValue(0);
$sheet->getCell('I12')->setValue(-1234.56);
$sheet->getCell('J12')->setValue('Text');
$format = new Accounting(
'$',
decimals: 3,
thousandsSeparator: false,
currencySymbolPosition: Accounting::TRAILING_SYMBOL,
negative: Currency::NEGATIVE_RED_MINUS
);
$sheet->getStyle('G12:J12')->applyFromArray(
[
'numberFormat' => [
'formatCode' => $format->format(),
],
]
);
$sheet->getCell('L2')->setValue(1234.56);
$sheet->getCell('L3')->setValue(0);
$sheet->getCell('L4')->setValue(-1234.56);
$format = new Accounting('$');
$sheet->getStyle('L2:L4')->applyFromArray(
[
'numberFormat' => [
'formatCode' => $format->format(),
],
]
);
$sheet->getCell('M2')->setValue(1234.56);
$sheet->getCell('M3')->setValue(0);
$sheet->getCell('M4')->setValue(-1234.56);
$format = new Accounting('€', currencySymbolPosition: Accounting::TRAILING_SYMBOL);
$sheet->getStyle('M2:M4')->applyFromArray(
[
'numberFormat' => [
'formatCode' => $format->format(),
],
]
);
$sheet->getColumnDimension('A')->setAutoSize(true);
$sheet->getColumnDimension('G')->setAutoSize(true);
$sheet->getColumnDimension('I')->setAutoSize(true);
$sheet->getColumnDimension('L')->setAutoSize(true);
$sheet->getColumnDimension('M')->setAutoSize(true);
$sheet->setSelectedCells('J1');
// second sheet
$helper->log('Second sheet - Currency Wizard');
$sheet = $spreadsheet->createSheet();
$sheet->setTitle('Currency');
$sheet->getCell('A1')->setValue('Currency');
$sheet->getCell('B1')->setValue('Decimals');
$sheet->getCell('C1')->setValue('ThouSep');
$sheet->getCell('D1')->setValue('Lead');
$sheet->getCell('E1')->setValue('Spacing');
$sheet->getCell('F1')->setValue('Negative');
$sheet->getCell('G1')->setValue('Pos');
$sheet->getCell('H1')->setValue('Zero');
$sheet->getCell('I1')->setValue('Neg');
$sheet->getCell('J1')->setValue('Text');
$sheet->freezePane('A2');
$sheet->getComment('E1')->getText()->createText('ignored, always false for Currency');
$sheet->getCell('A2')->setValue('CurrUSD');
$sheet->getCell('G2')->setValue(1234.56);
$sheet->getCell('H2')->setValue(0);
$sheet->getCell('I2')->setValue(-1234.56);
$sheet->getCell('J2')->setValue('text');
$sheet->getStyle('G2:J2')->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_CURRENCY_USD);
$sheet->getCell('A3')->setValue('CurrEur');
$sheet->getCell('G3')->setValue(1234.56);
$sheet->getCell('H3')->setValue(0);
$sheet->getCell('I3')->setValue(-1234.56);
$sheet->getCell('J3')->setValue('Text');
$sheet->getStyle('G3:J3')->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_CURRENCY_EUR);
$sheet->getCell('A4')->setValue('CurrWiz¥');
$sheet->getCell('E4')->setValue(true);
$sheet->getCell('G4')->setValue(1234.56);
$sheet->getCell('H4')->setValue(0);
$sheet->getCell('I4')->setValue(-1234.56);
$sheet->getCell('J4')->setValue('Text');
$sheet->getStyle('G4:J4')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Currency('¥', currencySymbolSpacing: true))->format(),
],
]
);
$sheet->getCell('A5')->setValue('StalePR¥');
$sheet->getCell('G5')->setValue(1234.56);
$sheet->getCell('H5')->setValue(0);
$sheet->getCell('I5')->setValue(-1234.56);
$sheet->getCell('J5')->setValue('Text');
$sheet->getStyle('G5:J5')->getNumberFormat()->setFormatCode('¥ #,##0');
$sheet->getCell('A6')->setValue('CurrWiz¥');
$sheet->getCell('E6')->setValue(true);
$sheet->getCell('F6')->setValue(Currency::NEGATIVE_MINUS);
$sheet->getCell('G6')->setValue(1234.56);
$sheet->getCell('H6')->setValue(0);
$sheet->getCell('I6')->setValue(-1234.56);
$sheet->getCell('J6')->setValue('Text');
$sheet->getStyle('G6:J6')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Currency('¥', currencySymbolSpacing: true, negative: Currency::NEGATIVE_MINUS))->format(),
],
]
);
$sheet->getCell('A7')->setValue('CurrWiz¥');
$sheet->getCell('E7')->setValue(false);
$sheet->getCell('F7')->setValue(Currency::NEGATIVE_MINUS);
$sheet->getCell('G7')->setValue(1234.56);
$sheet->getCell('H7')->setValue(0);
$sheet->getCell('I7')->setValue(-1234.56);
$sheet->getCell('J7')->setValue('Text');
$sheet->getStyle('G7:J7')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Currency('¥', currencySymbolSpacing: false, negative: Currency::NEGATIVE_MINUS))->format(),
],
]
);
$sheet->getCell('A8')->setValue('CurrWiz¥');
$sheet->getCell('E8')->setValue(false);
$sheet->getCell('F8')->setValue(Currency::NEGATIVE_PARENS);
$sheet->getCell('G8')->setValue(1234.56);
$sheet->getCell('H8')->setValue(0);
$sheet->getCell('I8')->setValue(-1234.56);
$sheet->getCell('J8')->setValue('Text');
$sheet->getStyle('G8:J8')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Currency('¥', currencySymbolSpacing: false, negative: Currency::NEGATIVE_PARENS))->format(),
],
]
);
$sheet->getCell('A9')->setValue('CurrW HUF');
$sheet->getCell('E9')->setValue(true);
$sheet->getCell('G9')->setValue(1234.56);
$sheet->getCell('H9')->setValue(0);
$sheet->getCell('I9')->setValue(-1234.56);
$sheet->getCell('J9')->setValue('Text');
$sheet->getStyle('G9:J9')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Currency('HUF', currencySymbolSpacing: true))->format(),
],
]
);
$sheet->getCell('A10')->setValue('CurrW HUF');
$sheet->getCell('E10')->setValue(true);
$sheet->getCell('F10')->setValue(Currency::NEGATIVE_RED_PARENS);
$sheet->getCell('G10')->setValue(1234.56);
$sheet->getCell('H10')->setValue(0);
$sheet->getCell('I10')->setValue(-1234.56);
$sheet->getCell('J10')->setValue('Text');
$sheet->getStyle('G10:J10')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Currency('HUF', currencySymbolSpacing: true, negative: Currency::NEGATIVE_RED_PARENS))->format(),
],
]
);
$sheet->getCell('A11')->setValue('CurrW Kazakh');
$sheet->getCell('D11')->setValue(false);
$sheet->getCell('G11')->setValue(1234.56);
$sheet->getCell('H11')->setValue(0);
$sheet->getCell('I11')->setValue(-1234.56);
$sheet->getCell('J11')->setValue('Text');
$sheet->getStyle('G11:J11')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new Currency('₸', currencySymbolPosition: Accounting::TRAILING_SYMBOL))->format(),
],
]
);
$sheet->getCell('A12')->setValue('CurrW $');
$sheet->getCell('B12')->setValue(3);
$sheet->getCell('C12')->setValue(false);
$sheet->getCell('D12')->setValue(false);
$sheet->getCell('F12')->setValue(Currency::NEGATIVE_RED_MINUS);
$sheet->getCell('G12')->setValue(1234.56);
$sheet->getCell('H12')->setValue(0);
$sheet->getCell('I12')->setValue(-1234.56);
$sheet->getCell('J12')->setValue('Text');
$format = new Currency(
'$',
decimals: 3,
thousandsSeparator: false,
currencySymbolPosition: Currency::TRAILING_SYMBOL,
negative: Currency::NEGATIVE_RED_MINUS
);
$sheet->getStyle('G12:J12')->applyFromArray(
[
'numberFormat' => [
'formatCode' => $format->format(),
],
]
);
$sheet->getColumnDimension('A')->setAutoSize(true);
$sheet->getColumnDimension('G')->setAutoSize(true);
$sheet->getColumnDimension('H')->setAutoSize(true);
$sheet->getColumnDimension('I')->setAutoSize(true);
$sheet->setSelectedCells('J1');
// third sheet
$helper->log('Third sheet - CurrencyBase Wizard');
$sheet = $spreadsheet->createSheet();
$sheet->setTitle('CurrencyBase');
$sheet->getCell('A1')->setValue('Currency');
$sheet->getCell('B1')->setValue('Decimals');
$sheet->getCell('C1')->setValue('ThouSep');
$sheet->getCell('D1')->setValue('Lead');
$sheet->getCell('E1')->setValue('Spacing');
$sheet->getCell('F1')->setValue('Negative');
$sheet->getCell('G1')->setValue('Pos');
$sheet->getCell('H1')->setValue('Zero');
$sheet->getCell('I1')->setValue('Neg');
$sheet->getCell('J1')->setValue('Text');
$sheet->freezePane('A2');
$sheet->getCell('A2')->setValue('StaleAct¥');
$sheet->getCell('G2')->setValue(1234.56);
$sheet->getCell('H2')->setValue(0);
$sheet->getCell('I2')->setValue(-1234.56);
$sheet->getCell('J2')->setValue('Text');
$sheet->getStyle('G2:J2')->getNumberFormat()->setFormatCode('_("¥"* #,##0.00_);_("¥"* -#,##0.00_);_("¥"* "-"??_);_(@_)');
$sheet->getCell('A3')->setValue('CurBase ¥');
$sheet->getCell('E3')->setValue(true);
$sheet->getCell('F3')->setValue(Currency::NEGATIVE_MINUS);
$sheet->getCell('G3')->setValue(1234.56);
$sheet->getCell('H3')->setValue(0);
$sheet->getCell('I3')->setValue(-1234.56);
$sheet->getCell('J3')->setValue('Text');
$sheet->getStyle('G3:J3')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new CurrencyBase('¥', currencySymbolSpacing: true, negative: Currency::NEGATIVE_MINUS))->format(),
],
]
);
$sheet->getCell('G4')->setValue(-1234.56);
$sheet->getStyle('G4')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new CurrencyBase('¥', currencySymbolSpacing: true, negative: Currency::NEGATIVE_MINUS))->format(),
],
]
);
$sheet->getCell('G5')->setValue(0);
$sheet->getStyle('G5')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new CurrencyBase('¥', currencySymbolSpacing: true, negative: Currency::NEGATIVE_MINUS))->format(),
],
]
);
$sheet->getCell('A6')->setValue('StaleCur¥');
$sheet->getCell('G6')->setValue(1234.56);
$sheet->getCell('H6')->setValue(0);
$sheet->getCell('I6')->setValue(-1234.56);
$sheet->getCell('J6')->setValue('Text');
$sheet->getStyle('G6:J6')->getNumberFormat()->setFormatCode('¥ #,##0');
$sheet->getCell('A7')->setValue('CurBase ¥');
$sheet->getCell('B7')->setValue(0);
$sheet->getCell('G7')->setValue(1234.56);
$sheet->getCell('H7')->setValue(0);
$sheet->getCell('I7')->setValue(-1234.56);
$sheet->getCell('J7')->setValue('Text');
$sheet->getStyle('G7:J7')->applyFromArray(
[
'numberFormat' => [
'formatCode' => (new CurrencyBase('¥', 0))->format(),
],
]
);
$sheet->getColumnDimension('A')->setAutoSize(true);
$sheet->getColumnDimension('G')->setAutoSize(true);
$sheet->getColumnDimension('H')->setAutoSize(true);
$sheet->getColumnDimension('I')->setAutoSize(true);
$sheet->setSelectedCells('J1');
$spreadsheet->setActiveSheetIndex(0);
// Save
$helper->write($spreadsheet, __FILE__, ['Xls', 'Xlsx']);
$spreadsheet->disconnectWorksheets();
@@ -162,6 +162,8 @@ class Formatter extends BaseFormatter
if (
// Check for date/time characters (not inside quotes)
(preg_match('/(\[\$[A-Z]*-[0-9A-F]*\])*[hmsdy](?=(?:[^"]|"[^"]*")*$)/miu', $format))
// Look out for Currency formats Issue 4124
&& !(preg_match('/\[\$[A-Z]{3}\]/miu', $format))
// A date/time with a decimal time shouldn't have a digit placeholder before the decimal point
&& (preg_match('/[0\?#]\.(?![^\[]*\])/miu', $format) === 0)
) {
@@ -236,6 +236,7 @@ class NumberFormatter extends BaseFormatter
if (preg_match('/\[\$(.*)\]/u', $format, $m)) {
// Currency or Accounting
$value = preg_replace('/-0+(( |\\xc2\\xa0))?\\[/', '- [', (string) $value) ?? $value;
$currencyCode = $m[1];
[$currencyCode] = explode('-', $currencyCode);
if ($currencyCode == '') {
@@ -5,40 +5,11 @@ namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;
use NumberFormatter;
use PhpOffice\PhpSpreadsheet\Exception;
class Accounting extends Currency
class Accounting extends CurrencyBase
{
/**
* @param string $currencyCode the currency symbol or code to display for this mask
* @param int $decimals number of decimal places to display, in the range 0-30
* @param bool $thousandsSeparator indicator whether the thousands separator should be used, or not
* @param bool $currencySymbolPosition indicates whether the currency symbol comes before or after the value
* Possible values are Currency::LEADING_SYMBOL and Currency::TRAILING_SYMBOL
* @param bool $currencySymbolSpacing indicates whether there is spacing between the currency symbol and the value
* Possible values are Currency::SYMBOL_WITH_SPACING and Currency::SYMBOL_WITHOUT_SPACING
* @param ?string $locale Set the locale for the currency format; or leave as the default null.
* If provided, Locale values must be a valid formatted locale string (e.g. 'en-GB', 'fr', uz-Arab-AF).
* Note that setting a locale will override any other settings defined in this class
* other than the currency code; or decimals (unless the decimals value is set to 0).
*
* @throws Exception If a provided locale code is not a valid format
*/
public function __construct(
string $currencyCode = '$',
int $decimals = 2,
bool $thousandsSeparator = true,
bool $currencySymbolPosition = self::LEADING_SYMBOL,
bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING,
?string $locale = null,
bool $stripLeadingRLM = self::DEFAULT_STRIP_LEADING_RLM
) {
$this->setCurrencyCode($currencyCode);
$this->setThousandsSeparator($thousandsSeparator);
$this->setDecimals($decimals);
$this->setCurrencySymbolPosition($currencySymbolPosition);
$this->setCurrencySymbolSpacing($currencySymbolSpacing);
$this->setLocale($locale);
$this->stripLeadingRLM = $stripLeadingRLM;
}
protected ?bool $overrideSpacing = true;
protected ?string $overrideNegative = self::NEGATIVE_PARENS;
/**
* @throws Exception if the Intl extension and ICU version don't support Accounting formats
@@ -76,27 +47,4 @@ class Accounting extends Currency
return "[\${$this->currencyCode}-{$this->locale}]";
}
public function format(): string
{
if ($this->localeFormat !== null) {
return $this->localeFormat;
}
return sprintf(
'_-%s%s%s0%s%s%s_-',
$this->currencySymbolPosition === self::LEADING_SYMBOL ? $this->formatCurrencyCode() : null,
(
$this->currencySymbolPosition === self::LEADING_SYMBOL
&& $this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING
) ? "\u{a0}" : '',
$this->thousandsSeparator ? '#,##' : null,
$this->decimals > 0 ? '.' . str_repeat('0', $this->decimals) : null,
(
$this->currencySymbolPosition === self::TRAILING_SYMBOL
&& $this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING
) ? "\u{a0}" : '',
$this->currencySymbolPosition === self::TRAILING_SYMBOL ? $this->formatCurrencyCode() : null
);
}
}
@@ -2,124 +2,9 @@
namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;
use NumberFormatter;
use PhpOffice\PhpSpreadsheet\Exception;
class Currency extends Number
class Currency extends CurrencyBase
{
public const LEADING_SYMBOL = true;
protected ?bool $overrideSpacing = false;
public const TRAILING_SYMBOL = false;
public const SYMBOL_WITH_SPACING = true;
public const SYMBOL_WITHOUT_SPACING = false;
protected string $currencyCode = '$';
protected bool $currencySymbolPosition = self::LEADING_SYMBOL;
protected bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING;
protected const DEFAULT_STRIP_LEADING_RLM = false;
protected bool $stripLeadingRLM = self::DEFAULT_STRIP_LEADING_RLM;
/**
* @param string $currencyCode the currency symbol or code to display for this mask
* @param int $decimals number of decimal places to display, in the range 0-30
* @param bool $thousandsSeparator indicator whether the thousands separator should be used, or not
* @param bool $currencySymbolPosition indicates whether the currency symbol comes before or after the value
* Possible values are Currency::LEADING_SYMBOL and Currency::TRAILING_SYMBOL
* @param bool $currencySymbolSpacing indicates whether there is spacing between the currency symbol and the value
* Possible values are Currency::SYMBOL_WITH_SPACING and Currency::SYMBOL_WITHOUT_SPACING
* @param ?string $locale Set the locale for the currency format; or leave as the default null.
* If provided, Locale values must be a valid formatted locale string (e.g. 'en-GB', 'fr', uz-Arab-AF).
* Note that setting a locale will override any other settings defined in this class
* other than the currency code; or decimals (unless the decimals value is set to 0).
* @param bool $stripLeadingRLM remove leading RLM added with
* ICU 72.1+.
*
* @throws Exception If a provided locale code is not a valid format
*/
public function __construct(
string $currencyCode = '$',
int $decimals = 2,
bool $thousandsSeparator = true,
bool $currencySymbolPosition = self::LEADING_SYMBOL,
bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING,
?string $locale = null,
bool $stripLeadingRLM = self::DEFAULT_STRIP_LEADING_RLM
) {
$this->setCurrencyCode($currencyCode);
$this->setThousandsSeparator($thousandsSeparator);
$this->setDecimals($decimals);
$this->setCurrencySymbolPosition($currencySymbolPosition);
$this->setCurrencySymbolSpacing($currencySymbolSpacing);
$this->setLocale($locale);
$this->stripLeadingRLM = $stripLeadingRLM;
}
public function setCurrencyCode(string $currencyCode): void
{
$this->currencyCode = $currencyCode;
}
public function setCurrencySymbolPosition(bool $currencySymbolPosition = self::LEADING_SYMBOL): void
{
$this->currencySymbolPosition = $currencySymbolPosition;
}
public function setCurrencySymbolSpacing(bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING): void
{
$this->currencySymbolSpacing = $currencySymbolSpacing;
}
public function setStripLeadingRLM(bool $stripLeadingRLM): void
{
$this->stripLeadingRLM = $stripLeadingRLM;
}
protected function getLocaleFormat(): string
{
$formatter = new Locale($this->fullLocale, NumberFormatter::CURRENCY);
$mask = $formatter->format($this->stripLeadingRLM);
if ($this->decimals === 0) {
$mask = (string) preg_replace('/\.0+/miu', '', $mask);
}
return str_replace('¤', $this->formatCurrencyCode(), $mask);
}
private function formatCurrencyCode(): string
{
if ($this->locale === null) {
return $this->currencyCode;
}
return "[\${$this->currencyCode}-{$this->locale}]";
}
public function format(): string
{
if ($this->localeFormat !== null) {
return $this->localeFormat;
}
return sprintf(
'%s%s%s0%s%s%s',
$this->currencySymbolPosition === self::LEADING_SYMBOL ? $this->formatCurrencyCode() : null,
(
$this->currencySymbolPosition === self::LEADING_SYMBOL
&& $this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING
) ? "\u{a0}" : '',
$this->thousandsSeparator ? '#,##' : null,
$this->decimals > 0 ? '.' . str_repeat('0', $this->decimals) : null,
(
$this->currencySymbolPosition === self::TRAILING_SYMBOL
&& $this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING
) ? "\u{a0}" : '',
$this->currencySymbolPosition === self::TRAILING_SYMBOL ? $this->formatCurrencyCode() : null
);
}
protected ?string $overrideNegative = null;
}
@@ -0,0 +1,260 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;
use NumberFormatter;
use PhpOffice\PhpSpreadsheet\Exception;
class CurrencyBase extends Number
{
public const LEADING_SYMBOL = true;
public const TRAILING_SYMBOL = false;
public const SYMBOL_WITH_SPACING = true;
public const SYMBOL_WITHOUT_SPACING = false;
protected string $currencyCode = '$';
protected bool $currencySymbolPosition = self::LEADING_SYMBOL;
protected bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING;
protected const DEFAULT_STRIP_LEADING_RLM = false;
protected bool $stripLeadingRLM = self::DEFAULT_STRIP_LEADING_RLM;
public const NEGATIVE_MINUS = '-';
public const NEGATIVE_RED_MINUS = 'red-';
public const NEGATIVE_PARENS = '()';
public const NEGATIVE_RED_PARENS = 'red()';
protected const NEGATIVE_START = [
self::NEGATIVE_MINUS => '-',
self::NEGATIVE_RED_MINUS => '-',
self::NEGATIVE_PARENS => '\\(',
self::NEGATIVE_RED_PARENS => '\\(',
];
protected const NEGATIVE_END = [
self::NEGATIVE_MINUS => '',
self::NEGATIVE_RED_MINUS => '',
self::NEGATIVE_PARENS => '\\)',
self::NEGATIVE_RED_PARENS => '\\)',
];
protected const NEGATIVE_COLOR = [
self::NEGATIVE_RED_MINUS => '[Red]',
self::NEGATIVE_RED_PARENS => '[Red]',
];
public const DEFAULT_NEGATIVE = self::NEGATIVE_MINUS;
protected string $negative = self::NEGATIVE_MINUS;
protected ?bool $overrideSpacing = null;
protected ?string $overrideNegative = null;
// Not sure why original code uses nbsp
private string $spaceOrNbsp = ' '; // or "\u{a0}"
/**
* @param string $currencyCode the currency symbol or code to display for this mask
* @param int $decimals number of decimal places to display, in the range 0-30
* @param bool $thousandsSeparator indicator whether the thousands separator should be used, or not
* @param bool $currencySymbolPosition indicates whether the currency symbol comes before or after the value
* Possible values are Currency::LEADING_SYMBOL and Currency::TRAILING_SYMBOL
* @param bool $currencySymbolSpacing indicates whether there is spacing between the currency symbol and the value
* Possible values are Currency::SYMBOL_WITH_SPACING and Currency::SYMBOL_WITHOUT_SPACING
* However, Currency always uses WITHOUT and Accounting always uses WITH
* @param ?string $locale Set the locale for the currency format; or leave as the default null.
* If provided, Locale values must be a valid formatted locale string (e.g. 'en-GB', 'fr', uz-Arab-AF).
* Note that setting a locale will override any other settings defined in this class
* other than the currency code; or decimals (unless the decimals value is set to 0).
* @param bool $stripLeadingRLM remove leading RLM added with
* ICU 72.1+.
* @param string $negative How to display negative numbers.
* Always use parentheses for Accounting.
* 4 options for Currency.
*
* @throws Exception If a provided locale code is not a valid format
*/
public function __construct(
string $currencyCode = '$',
int $decimals = 2,
bool $thousandsSeparator = true,
bool $currencySymbolPosition = self::LEADING_SYMBOL,
bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING,
?string $locale = null,
bool $stripLeadingRLM = self::DEFAULT_STRIP_LEADING_RLM,
string $negative = self::NEGATIVE_MINUS
) {
$this->setCurrencyCode($currencyCode);
$this->setThousandsSeparator($thousandsSeparator);
$this->setDecimals($decimals);
$this->setCurrencySymbolPosition($currencySymbolPosition);
$this->setCurrencySymbolSpacing($currencySymbolSpacing);
$this->setLocale($locale);
$this->stripLeadingRLM = $stripLeadingRLM;
$this->negative = $negative;
}
public function setCurrencyCode(string $currencyCode): void
{
$this->currencyCode = $currencyCode;
}
public function setCurrencySymbolPosition(bool $currencySymbolPosition = self::LEADING_SYMBOL): void
{
$this->currencySymbolPosition = $currencySymbolPosition;
}
public function setCurrencySymbolSpacing(bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING): void
{
$this->currencySymbolSpacing = $currencySymbolSpacing;
}
public function setStripLeadingRLM(bool $stripLeadingRLM): void
{
$this->stripLeadingRLM = $stripLeadingRLM;
}
public function setNegative(string $negative): void
{
$this->negative = $negative;
}
protected function getLocaleFormat(): string
{
$formatter = new Locale($this->fullLocale, NumberFormatter::CURRENCY);
$mask = $formatter->format($this->stripLeadingRLM);
if ($this->decimals === 0) {
$mask = (string) preg_replace('/\.0+/miu', '', $mask);
}
return str_replace('¤', $this->formatCurrencyCode(), $mask);
}
private function formatCurrencyCode(): string
{
if ($this->locale === null) {
return $this->currencyCode;
}
return "[\${$this->currencyCode}-{$this->locale}]";
}
public function format(): string
{
if ($this->localeFormat !== null) {
return $this->localeFormat;
}
$symbolWithSpacing = $this->overrideSpacing ?? ($this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING);
$negative = $this->overrideNegative ?? $this->negative;
// format if positive
$format = '_(';
if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
$format .= '"' . $this->currencyCode . '"';
if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
if ($symbolWithSpacing) {
$format .= '*' . $this->spaceOrNbsp;
}
}
$format .= $this->thousandsSeparator ? '#,##0' : '0';
if ($this->decimals > 0) {
$format .= '.' . str_repeat('0', $this->decimals);
}
if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
if ($symbolWithSpacing) {
$format .= $this->spaceOrNbsp;
} elseif (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
$format .= '[$' . $this->currencyCode . ']';
}
$format .= '_)';
// format if negative
$format .= ';_(';
$format .= self::NEGATIVE_COLOR[$negative] ?? '';
$negativeStart = self::NEGATIVE_START[$negative] ?? '';
if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
if ($negativeStart === '-' && !$symbolWithSpacing) {
$format .= $negativeStart;
}
$format .= '"' . $this->currencyCode . '"';
if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
if ($symbolWithSpacing) {
$format .= '*' . $this->spaceOrNbsp;
}
if ($negativeStart === '\\(' || ($symbolWithSpacing && $negativeStart === '-')) {
$format .= $negativeStart;
}
} else {
$format .= self::NEGATIVE_START[$negative] ?? '';
}
$format .= $this->thousandsSeparator ? '#,##0' : '0';
if ($this->decimals > 0) {
$format .= '.' . str_repeat('0', $this->decimals);
}
$format .= self::NEGATIVE_END[$negative] ?? '';
if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
if ($symbolWithSpacing) {
// Do nothing - I can't figure out how to get
// everything to align if I put any kind of space here.
//$format .= "\u{2009}";
} elseif (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
$format .= '[$' . $this->currencyCode . ']';
}
if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
$format .= '_)';
} elseif ($symbolWithSpacing && $negativeStart === '-') {
$format .= ' ';
}
// format if zero
$format .= ';_(';
if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
$format .= '"' . $this->currencyCode . '"';
}
if ($symbolWithSpacing) {
if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
$format .= '*' . $this->spaceOrNbsp;
}
$format .= '"-"';
if ($this->decimals > 0) {
$format .= str_repeat('?', $this->decimals);
}
} else {
if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
$format .= $this->spaceOrNbsp;
}
$format .= '0';
if ($this->decimals > 0) {
$format .= '.' . str_repeat('0', $this->decimals);
}
}
if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
if ($symbolWithSpacing) {
$format .= $this->spaceOrNbsp;
}
$format .= '[$' . $this->currencyCode . ']';
}
$format .= '_)';
// format if text
$format .= ';_(@_)';
return $format;
}
}
@@ -456,6 +456,8 @@ class Worksheet extends WriterPart
{
// cols
if (count($worksheet->getColumnDimensions()) > 0) {
$activeSheet = $worksheet->getParent()?->getActiveSheetIndex();
$selectedCells = $worksheet->getSelectedCells();
$objWriter->startElement('cols');
$worksheet->calculateColumnWidths();
@@ -507,6 +509,10 @@ class Worksheet extends WriterPart
}
$objWriter->endElement();
if ($activeSheet !== null && $activeSheet >= 0) {
$worksheet->getParent()?->setActiveSheetIndex($activeSheet);
}
$worksheet->setSelectedCells($selectedCells);
}
}
@@ -6,6 +6,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Style\NumberFormat\Wizard;
use NumberFormatter;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Formatter;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Accounting;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Currency;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Number;
@@ -17,26 +18,31 @@ class AccountingTest extends TestCase
* @dataProvider providerAccounting
*/
public function testAccounting(
string $expectedResult,
string $expectedResultPositive,
string $expectedResultNegative,
string $expectedResultZero,
string $currencyCode,
int $decimals,
bool $thousandsSeparator,
bool $currencySymbolPosition,
bool $currencySymbolSpacing
bool $currencySymbolSpacing,
string $negative = Accounting::DEFAULT_NEGATIVE
): void {
$wizard = new Accounting($currencyCode, $decimals, $thousandsSeparator, $currencySymbolPosition, $currencySymbolSpacing);
self::assertSame($expectedResult, (string) $wizard);
$wizard = new Accounting($currencyCode, $decimals, $thousandsSeparator, $currencySymbolPosition, $currencySymbolSpacing, negative: $negative);
self::assertSame($expectedResultPositive, Formatter::toFormattedString(1234.56, $wizard->format()));
self::assertSame($expectedResultNegative, Formatter::toFormattedString(-1234.56, $wizard->format()));
self::assertSame($expectedResultZero, Formatter::toFormattedString(0, $wizard->format()));
}
public static function providerAccounting(): array
{
return [
["_-$*\u{a0}0_-", '$', 0, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
["_-$*\u{a0}#,##0_-", '$', 0, Number::WITH_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
['_-$*#,##0_-', '$', 0, Number::WITH_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITHOUT_SPACING],
["_-0.00\u{a0}€*_-", '€', 2, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
["_-#,##0.00\u{a0}€*_-", '€', 2, Number::WITH_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
['_-0.00€*_-', '€', 2, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITHOUT_SPACING],
[' $ 1235 ', ' $ (1235)', ' $ - ', '$', 0, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
[' $ 1,235 ', ' $ (1,235)', ' $ - ', '$', 0, Number::WITH_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
[' $ 1,235 ', ' $ (1,235)', ' $ - ', '$', 0, Number::WITH_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITHOUT_SPACING],
[' 1234.56 € ', ' (1234.56)€ ', ' - € ', '€', 2, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
[' 1,234.56 € ', ' (1,234.56)€ ', ' - € ', '€', 2, Number::WITH_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
[' 1234.560 € ', ' (1234.560)€ ', ' - € ', '€', 3, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITHOUT_SPACING],
];
}
@@ -6,6 +6,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Style\NumberFormat\Wizard;
use NumberFormatter;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Formatter;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Accounting;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Currency;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Number;
@@ -17,26 +18,32 @@ class CurrencyTest extends TestCase
* @dataProvider providerCurrency
*/
public function testCurrency(
string $expectedResult,
string $expectedResultPositive,
string $expectedResultNegative,
string $expectedResultZero,
string $currencyCode,
int $decimals,
bool $thousandsSeparator,
bool $currencySymbolPosition,
bool $currencySymbolSpacing
bool $currencySymbolSpacing,
string $negative = Currency::NEGATIVE_MINUS
): void {
$wizard = new Currency($currencyCode, $decimals, $thousandsSeparator, $currencySymbolPosition, $currencySymbolSpacing);
self::assertSame($expectedResult, (string) $wizard);
$wizard = new Currency($currencyCode, $decimals, $thousandsSeparator, $currencySymbolPosition, $currencySymbolSpacing, negative: $negative);
self::assertSame($expectedResultPositive, Formatter::toFormattedString(1234.56, $wizard->format()));
self::assertSame($expectedResultNegative, Formatter::toFormattedString(-1234.56, $wizard->format()));
self::assertSame($expectedResultZero, Formatter::toFormattedString(0, $wizard->format()));
}
public static function providerCurrency(): array
{
return [
["\$\u{a0}0", '$', 0, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
["\$\u{a0}#,##0", '$', 0, Number::WITH_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
['$#,##0', '$', 0, Number::WITH_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITHOUT_SPACING],
["0.00\u{a0}€", '€', 2, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
["#,##0.00\u{a0}€", '€', 2, Number::WITH_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
['0.00€', '€', 2, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITHOUT_SPACING],
[' $1235 ', ' -$1235', ' $0 ', '$', 0, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
[' $1,235 ', ' -$1,235', ' $0 ', '$', 0, Number::WITH_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
[' $1,235 ', ' -$1,235', ' $0 ', '$', 0, Number::WITH_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITHOUT_SPACING],
[' 1234.56€ ', ' -1234.56€ ', ' 0.00€ ', '€', 2, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
[' 1,234.56€ ', ' -1,234.56€ ', ' 0.00€ ', '€', 2, Number::WITH_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
[' 1234.56€ ', ' -1234.56€ ', ' 0.00€ ', '€', 2, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITHOUT_SPACING],
[' 1234.56€ ', ' (1234.56)€ ', ' 0.00€ ', '€', 2, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITHOUT_SPACING, Currency::NEGATIVE_PARENS],
];
}
@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Shared\File;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PHPUnit\Framework\TestCase;
class RetainActiveSheetAndCellsTest extends TestCase
{
public function testRetain(): void
{
$spreadsheet = new Spreadsheet();
$sheet1 = $spreadsheet->getActiveSheet();
$array = [
[1, 2, 3, 4, 5],
[11, 12, 13, 14, 15],
[21, 22, 23, 24, 25],
[31, 32, 33, 34, 35],
];
$sheet1->fromArray($array);
$sheet2 = $spreadsheet->createSheet();
$sheet2->fromArray($array);
$sheet3 = $spreadsheet->createSheet();
$sheet3->fromArray($array);
$sheet1->getStyle('A1')->getFont()->setName('Arial');
$sheet2->getStyle('A1')->getFont()->setName('Arial');
$sheet3->getStyle('A1')->getFont()->setName('Arial');
$sheet1->getColumnDimension('A')->setAutoSize(true);
$sheet2->getColumnDimension('A')->setAutoSize(true);
$sheet3->getColumnDimension('A')->setAutoSize(true);
$sheet1->setSelectedCells('B2');
$sheet2->setSelectedCells('C3');
$sheet3->setSelectedCells('D4');
$spreadsheet->setActiveSheetIndex(1);
$outfile = File::temporaryFilename();
$writer = new XlsxWriter($spreadsheet);
$writer->save($outfile);
unlink($outfile);
self::assertSame(1, $spreadsheet->getActiveSheetIndex());
self::assertSame('B2', $spreadsheet->getSheet(0)->getSelectedCells());
self::assertSame('C3', $spreadsheet->getSheet(1)->getSelectedCells());
self::assertSame('D4', $spreadsheet->getSheet(2)->getSelectedCells());
$spreadsheet->disconnectWorksheets();
}
}
+1
View File
@@ -1681,4 +1681,5 @@ return [
-12345.6789,
'#,##0.00;;"---"',
],
'issue 4124' => ['1 HUF', 1, '#,##0_-[$HUF]'],
];