Skip to content

Commit

Permalink
Wizards for defining Number Format masks for Percentages, Scientific,…
Browse files Browse the repository at this point in the history
… Numbers, and Currency
  • Loading branch information
MarkBaker committed Feb 1, 2023
1 parent fc8966e commit e789c08
Show file tree
Hide file tree
Showing 11 changed files with 294 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Added

- Support for configuring a Chart Title's overlay [PR #3325](https://github.com/PHPOffice/PhpSpreadsheet/pull/3325)
- Wizards for defining Number Format masks for Percentages, Scientific, Numbers, and Currency [PR #3334](https://github.com/PHPOffice/PhpSpreadsheet/pull/3334)

### Changed

Expand Down
68 changes: 68 additions & 0 deletions src/PhpSpreadsheet/Style/NumberFormat/Wizard/Currency.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;

class Currency 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;

public function __construct(
string $currencyCode = '$',
int $decimals = 2,
bool $thousandsSeparator = true,
bool $currencySymbolPosition = self::LEADING_SYMBOL,
bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING
) {
$this->setCurrencyCode($currencyCode);
$this->setThousandsSeparator($thousandsSeparator);
$this->setDecimals($decimals);
$this->setCurrencySymbolPosition($currencySymbolPosition);
$this->setCurrencySymbolSpacing($currencySymbolSpacing);
}

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 format(): string
{
return sprintf(
'%s%s%s0%s%s%s',
$this->currencySymbolPosition === self::LEADING_SYMBOL ? $this->currencyCode : null,
(
$this->currencySymbolPosition === self::LEADING_SYMBOL &&
$this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING
) ? ' ' : '',
$this->thousandsSeparator ? '#,##' : null,
$this->decimals > 0 ? '.' . str_repeat('0', $this->decimals) : null,
(
$this->currencySymbolPosition === self::TRAILING_SYMBOL &&
$this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING
) ? ' ' : '',
$this->currencySymbolPosition === self::TRAILING_SYMBOL ? $this->currencyCode : null
);
}
}
32 changes: 32 additions & 0 deletions src/PhpSpreadsheet/Style/NumberFormat/Wizard/Number.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;

class Number extends NumberBase implements Wizard
{
public const WITH_THOUSANDS_SEPARATOR = true;

public const WITHOUT_THOUSANDS_SEPARATOR = false;

protected bool $thousandsSeparator = true;

public function __construct(int $decimals = 2, bool $thousandsSeparator = self::WITH_THOUSANDS_SEPARATOR)
{
$this->setThousandsSeparator($thousandsSeparator);
$this->setDecimals($decimals);
}

public function setThousandsSeparator(bool $thousandsSeparator = self::WITH_THOUSANDS_SEPARATOR): void
{
$this->thousandsSeparator = $thousandsSeparator;
}

public function format(): string
{
return sprintf(
'%s0%s',
$this->thousandsSeparator ? '#,##' : null,
$this->decimals > 0 ? '.' . str_repeat('0', $this->decimals) : null
);
}
}
20 changes: 20 additions & 0 deletions src/PhpSpreadsheet/Style/NumberFormat/Wizard/NumberBase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;

abstract class NumberBase
{
protected const MAX_DECIMALS = 30;

protected int $decimals = 2;

public function setDecimals(int $decimals = 2): void
{
$this->decimals = ($decimals > self::MAX_DECIMALS) ? self::MAX_DECIMALS : max($decimals, 0);
}

public function __toString(): string
{
return $this->format();
}
}
19 changes: 19 additions & 0 deletions src/PhpSpreadsheet/Style/NumberFormat/Wizard/Percentage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;

class Percentage extends NumberBase implements Wizard
{
/**
* @param int $decimals number of decimal places to display, in the range 0-30
*/
public function __construct(int $decimals = 2)
{
$this->setDecimals($decimals);
}

public function format(): string
{
return sprintf('0%s%%', $this->decimals > 0 ? '.' . str_repeat('0', $this->decimals) : null);
}
}
19 changes: 19 additions & 0 deletions src/PhpSpreadsheet/Style/NumberFormat/Wizard/Scientific.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;

class Scientific extends NumberBase implements Wizard
{
/**
* @param int $decimals number of decimal places to display, in the range 0-30
*/
public function __construct(int $decimals = 2)
{
$this->setDecimals($decimals);
}

public function format(): string
{
return sprintf('0%sE+00', $this->decimals > 0 ? '.' . str_repeat('0', $this->decimals) : null);
}
}
8 changes: 8 additions & 0 deletions src/PhpSpreadsheet/Style/NumberFormat/Wizard/Wizard.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;

interface Wizard
{
public function format(): string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace PhpOffice\PhpSpreadsheetTests\Style\NumberFormat\Wizard;

use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Currency;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Number;
use PHPUnit\Framework\TestCase;

class CurrencyTest extends TestCase
{
/**
* @dataProvider providerCurrency
*/
public function testCurrency(
string $expectedResult,
string $currencyCode,
int $decimals,
bool $thousandsSeparator,
bool $currencySymbolPosition,
bool $currencySymbolSpacing
): void {
$wizard = new Currency($currencyCode, $decimals, $thousandsSeparator, $currencySymbolPosition, $currencySymbolSpacing);
self::assertSame($expectedResult, (string) $wizard);
}

public function providerCurrency(): array
{
return [
['$ 0', '$', 0, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::LEADING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
['$ #,##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 €', '', 2, Number::WITHOUT_THOUSANDS_SEPARATOR, Currency::TRAILING_SYMBOL, Currency::SYMBOL_WITH_SPACING],
['#,##0.00 €', '', 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],
];
}
}
30 changes: 30 additions & 0 deletions tests/PhpSpreadsheetTests/Style/NumberFormat/Wizard/NumberTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace PhpOffice\PhpSpreadsheetTests\Style\NumberFormat\Wizard;

use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Number;
use PHPUnit\Framework\TestCase;

class NumberTest extends TestCase
{
/**
* @dataProvider providerNumber
*/
public function testNumber(string $expectedResult, int $decimals, bool $thousandsSeparator): void
{
$wizard = new Number($decimals, $thousandsSeparator);
self::assertSame($expectedResult, (string) $wizard);
}

public function providerNumber(): array
{
return [
['0', 0, Number::WITHOUT_THOUSANDS_SEPARATOR],
['#,##0', 0, Number::WITH_THOUSANDS_SEPARATOR],
['0.0', 1, Number::WITHOUT_THOUSANDS_SEPARATOR],
['#,##0.0', 1, Number::WITH_THOUSANDS_SEPARATOR],
['0.00', 2, Number::WITHOUT_THOUSANDS_SEPARATOR],
['#,##0.00', 2, Number::WITH_THOUSANDS_SEPARATOR],
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace PhpOffice\PhpSpreadsheetTests\Style\NumberFormat\Wizard;

use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Percentage;
use PHPUnit\Framework\TestCase;

class PercentageTest extends TestCase
{
/**
* @dataProvider providerPercentage
*/
public function testPercentage(string $expectedResult, int $decimals): void
{
$wizard = new Percentage($decimals);
self::assertSame($expectedResult, (string) $wizard);
}

public function providerPercentage(): array
{
return [
['0%', 0],
['0.0%', 1],
['0.00%', 2],
['0.000%', 3],
['0%', -1],
['0.000000000000000000000000000000%', 31],
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace PhpOffice\PhpSpreadsheetTests\Style\NumberFormat\Wizard;

use PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard\Scientific;
use PHPUnit\Framework\TestCase;

class ScientificTest extends TestCase
{
/**
* @dataProvider providerScientific
*/
public function testScientific(string $expectedResult, int $decimals): void
{
$wizard = new Scientific($decimals);
self::assertSame($expectedResult, (string) $wizard);
}

public function providerScientific(): array
{
return [
['0E+00', 0],
['0.0E+00', 1],
['0.00E+00', 2],
['0.000E+00', 3],
['0E+00', -1],
['0.000000000000000000000000000000E+00', 31],
];
}
}

0 comments on commit e789c08

Please sign in to comment.