mirror of
https://github.com/ramsey/uuid.git
synced 2026-06-15 16:07:55 +03:00
Deprecate BigNumberConverter and BigNumberTimeConverter
This commit is contained in:
@@ -14,53 +14,42 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ramsey\Uuid\Converter\Number;
|
||||
|
||||
use Moontoast\Math\BigNumber;
|
||||
use Ramsey\Uuid\Converter\DependencyCheckTrait;
|
||||
use Ramsey\Uuid\Converter\NumberConverterInterface;
|
||||
use Ramsey\Uuid\Converter\NumberStringTrait;
|
||||
use Ramsey\Uuid\Exception\InvalidArgumentException;
|
||||
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
|
||||
use Ramsey\Uuid\Math\BrickMathCalculator;
|
||||
|
||||
/**
|
||||
* BigNumberConverter uses moontoast/math to convert UUIDs from hexadecimal
|
||||
* characters into string representations of integers and vice versa
|
||||
* Previously used to integrate moontoast/math as a bignum arithmetic library,
|
||||
* BigNumberConverter is deprecated in favor of ArbitraryPrecisionNumberConverter
|
||||
*
|
||||
* @deprecated Transition to {@see GenericNumberConverter}.
|
||||
*/
|
||||
class BigNumberConverter implements NumberConverterInterface
|
||||
{
|
||||
use DependencyCheckTrait;
|
||||
use NumberStringTrait;
|
||||
/**
|
||||
* @var NumberConverterInterface
|
||||
*/
|
||||
private $converter;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->converter = new GenericNumberConverter(new BrickMathCalculator());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException if $hex is not a hexadecimal string
|
||||
* @throws UnsatisfiedDependencyException if the chosen converter is not present
|
||||
*
|
||||
* @inheritDoc
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
public function fromHex(string $hex): string
|
||||
{
|
||||
$this->checkMoontoastMathLibrary();
|
||||
$this->checkHexadecimalString($hex, 'hex');
|
||||
|
||||
/** @psalm-suppress ImpureMethodCall */
|
||||
return BigNumber::convertToBase10($hex, 16);
|
||||
return $this->converter->fromHex($hex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException if $integer is not an integer string
|
||||
* @throws UnsatisfiedDependencyException if the chosen converter is not present
|
||||
*
|
||||
* @inheritDoc
|
||||
*
|
||||
* @psalm-pure
|
||||
*/
|
||||
public function toHex(string $number): string
|
||||
{
|
||||
$this->checkMoontoastMathLibrary();
|
||||
$this->checkIntegerString($number, 'number');
|
||||
|
||||
/** @psalm-suppress ImpureMethodCall */
|
||||
return BigNumber::convertFromBase10($number, 16);
|
||||
return $this->converter->toHex($number);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,81 +14,42 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ramsey\Uuid\Converter\Time;
|
||||
|
||||
use Moontoast\Math\BigNumber;
|
||||
use Ramsey\Uuid\Converter\DependencyCheckTrait;
|
||||
use Ramsey\Uuid\Converter\NumberStringTrait;
|
||||
use Ramsey\Uuid\Converter\TimeConverterInterface;
|
||||
use Ramsey\Uuid\Exception\InvalidArgumentException;
|
||||
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
|
||||
use Ramsey\Uuid\Math\BrickMathCalculator;
|
||||
|
||||
/**
|
||||
* BigNumberTimeConverter uses the moontoast/math library's `BigNumber` to
|
||||
* provide facilities for converting parts of time into representations that may
|
||||
* be used in UUIDs
|
||||
* Previously used to integrate moontoast/math as a bignum arithmetic library,
|
||||
* BigNumberTimeConverter is deprecated in favor of ArbitraryPrecisionTimeConverter
|
||||
*
|
||||
* @deprecated Transition to {@see GenericTimeConverter}.
|
||||
*/
|
||||
class BigNumberTimeConverter implements TimeConverterInterface
|
||||
{
|
||||
use DependencyCheckTrait;
|
||||
use NumberStringTrait;
|
||||
/**
|
||||
* @var TimeConverterInterface
|
||||
*/
|
||||
private $converter;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->converter = new GenericTimeConverter(new BrickMathCalculator());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException if $seconds or $microseconds are not integer strings
|
||||
* @throws UnsatisfiedDependencyException if the chosen converter is not present
|
||||
*
|
||||
* @inheritDoc
|
||||
*
|
||||
* @psalm-pure
|
||||
* @psalm-suppress ImpureMethodCall The use of the external moontoast/math
|
||||
* library causes Psalm to complain about impure method calls.
|
||||
*/
|
||||
public function calculateTime(string $seconds, string $microSeconds): array
|
||||
{
|
||||
$this->checkMoontoastMathLibrary();
|
||||
$this->checkIntegerString($seconds, 'seconds');
|
||||
$this->checkIntegerString($microSeconds, 'microSeconds');
|
||||
|
||||
$uuidTime = new BigNumber('0');
|
||||
|
||||
$sec = new BigNumber($seconds);
|
||||
$sec->multiply('10000000');
|
||||
|
||||
$usec = new BigNumber($microSeconds);
|
||||
$usec->multiply('10');
|
||||
|
||||
$uuidTime
|
||||
->add($sec)
|
||||
->add($usec)
|
||||
->add('122192928000000000');
|
||||
|
||||
$uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16));
|
||||
|
||||
return [
|
||||
'low' => substr($uuidTimeHex, 8),
|
||||
'mid' => substr($uuidTimeHex, 4, 4),
|
||||
'hi' => substr($uuidTimeHex, 0, 4),
|
||||
];
|
||||
return $this->converter->calculateTime($seconds, $microSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException if $timestamp is not an integer string
|
||||
* @throws UnsatisfiedDependencyException if the chosen converter is not present
|
||||
*
|
||||
* @inheritDoc
|
||||
*
|
||||
* @psalm-pure
|
||||
* @psalm-suppress ImpureMethodCall The use of the external moontoast/math
|
||||
* library causes Psalm to complain about impure method calls.
|
||||
*/
|
||||
public function convertTime(string $timestamp): string
|
||||
{
|
||||
$this->checkMoontoastMathLibrary();
|
||||
$this->checkIntegerString($timestamp, 'timestamp');
|
||||
|
||||
$ts = new BigNumber($timestamp, 20);
|
||||
$ts->subtract('122192928000000000');
|
||||
$ts->divide('10000000.0');
|
||||
$ts->round();
|
||||
|
||||
return $ts->getValue();
|
||||
return $this->converter->convertTime($timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
+31
-21
@@ -21,12 +21,12 @@ use Ramsey\Uuid\Builder\UuidBuilderInterface;
|
||||
use Ramsey\Uuid\Codec\CodecInterface;
|
||||
use Ramsey\Uuid\Codec\GuidStringCodec;
|
||||
use Ramsey\Uuid\Codec\StringCodec;
|
||||
use Ramsey\Uuid\Converter\Number\BigNumberConverter;
|
||||
use Ramsey\Uuid\Converter\Number\DegradedNumberConverter;
|
||||
use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
|
||||
use Ramsey\Uuid\Converter\Number\GmpConverter;
|
||||
use Ramsey\Uuid\Converter\NumberConverterInterface;
|
||||
use Ramsey\Uuid\Converter\Time\BigNumberTimeConverter;
|
||||
use Ramsey\Uuid\Converter\Time\DegradedTimeConverter;
|
||||
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
|
||||
use Ramsey\Uuid\Converter\Time\GmpTimeConverter;
|
||||
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
|
||||
use Ramsey\Uuid\Converter\TimeConverterInterface;
|
||||
@@ -38,6 +38,8 @@ use Ramsey\Uuid\Generator\TimeGeneratorInterface;
|
||||
use Ramsey\Uuid\Guid\DegradedGuidBuilder;
|
||||
use Ramsey\Uuid\Guid\GuidBuilder;
|
||||
use Ramsey\Uuid\Nonstandard\DegradedUuidBuilder as NonstandardDegradedUuidBuilder;
|
||||
use Ramsey\Uuid\Math\BrickMathCalculator;
|
||||
use Ramsey\Uuid\Math\CalculatorInterface;
|
||||
use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
|
||||
use Ramsey\Uuid\Provider\Node\FallbackNodeProvider;
|
||||
use Ramsey\Uuid\Provider\Node\RandomNodeProvider;
|
||||
@@ -121,6 +123,11 @@ class FeatureSet
|
||||
*/
|
||||
private $validator;
|
||||
|
||||
/**
|
||||
* @var CalculatorInterface
|
||||
*/
|
||||
private $calculator;
|
||||
|
||||
/**
|
||||
* @param bool $useGuids True build UUIDs using the GuidStringCodec
|
||||
* @param bool $force32Bit True to force the use of 32-bit functionality
|
||||
@@ -148,6 +155,7 @@ class FeatureSet
|
||||
$this->ignoreSystemNode = $ignoreSystemNode;
|
||||
$this->enablePecl = $enablePecl;
|
||||
|
||||
$this->calculator = new BrickMathCalculator();
|
||||
$this->numberConverter = $this->buildNumberConverter();
|
||||
$this->timeConverter = $this->buildTimeConverter();
|
||||
$this->builder = $this->buildUuidBuilder($useGuids);
|
||||
@@ -166,6 +174,14 @@ class FeatureSet
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the calculator configured for this environment
|
||||
*/
|
||||
public function getCalculator(): CalculatorInterface
|
||||
{
|
||||
return $this->calculator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the codec configured for this environment
|
||||
*/
|
||||
@@ -214,6 +230,14 @@ class FeatureSet
|
||||
return $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the calculator to use in this environment
|
||||
*/
|
||||
public function setCalculator(CalculatorInterface $calculator): void
|
||||
{
|
||||
$this->calculator = $calculator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time provider to use in this environment
|
||||
*/
|
||||
@@ -264,15 +288,7 @@ class FeatureSet
|
||||
*/
|
||||
private function buildNumberConverter(): NumberConverterInterface
|
||||
{
|
||||
if ($this->hasGmp()) {
|
||||
return new GmpConverter();
|
||||
}
|
||||
|
||||
if ($this->hasBigNumber()) {
|
||||
return new BigNumberConverter();
|
||||
}
|
||||
|
||||
return new DegradedNumberConverter();
|
||||
return new GenericNumberConverter($this->getCalculator());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,19 +323,13 @@ class FeatureSet
|
||||
*/
|
||||
private function buildTimeConverter(): TimeConverterInterface
|
||||
{
|
||||
$genericConverter = new GenericTimeConverter($this->getCalculator());
|
||||
|
||||
if ($this->is64BitSystem()) {
|
||||
return new PhpTimeConverter();
|
||||
return new PhpTimeConverter($genericConverter);
|
||||
}
|
||||
|
||||
if ($this->hasGmp()) {
|
||||
return new GmpTimeConverter();
|
||||
}
|
||||
|
||||
if ($this->hasBigNumber()) {
|
||||
return new BigNumberTimeConverter();
|
||||
}
|
||||
|
||||
return new DegradedTimeConverter();
|
||||
return $genericConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,62 +4,18 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ramsey\Uuid\Test\Converter\Number;
|
||||
|
||||
use AspectMock\Test as AspectMock;
|
||||
use Ramsey\Uuid\Converter\Number\BigNumberConverter;
|
||||
use Ramsey\Uuid\Exception\InvalidArgumentException;
|
||||
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
|
||||
use Ramsey\Uuid\Test\TestCase;
|
||||
|
||||
class BigNumberConverterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
public function testFromHexThrowsExceptionWhenMoontoastMathNotPresent(): void
|
||||
{
|
||||
$classExists = AspectMock::func(
|
||||
'Ramsey\Uuid\Converter',
|
||||
'class_exists',
|
||||
false
|
||||
);
|
||||
|
||||
$converter = new BigNumberConverter();
|
||||
|
||||
$this->expectException(UnsatisfiedDependencyException::class);
|
||||
$this->expectExceptionMessage('moontoast/math must be present to use this converter');
|
||||
|
||||
$converter->fromHex('abcd');
|
||||
$classExists->verifyInvokedOnce(['Moontoast\Math\BigNumber']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
public function testToHexThrowsExceptionWhenMoontoastMathNotPresent(): void
|
||||
{
|
||||
$classExists = AspectMock::func(
|
||||
'Ramsey\Uuid\Converter',
|
||||
'class_exists',
|
||||
false
|
||||
);
|
||||
|
||||
$converter = new BigNumberConverter();
|
||||
|
||||
$this->expectException(UnsatisfiedDependencyException::class);
|
||||
$this->expectExceptionMessage('moontoast/math must be present to use this converter');
|
||||
|
||||
$converter->toHex('1234');
|
||||
$classExists->verifyInvokedOnce(['Moontoast\Math\BigNumber']);
|
||||
}
|
||||
|
||||
public function testFromHexThrowsExceptionWhenStringDoesNotContainOnlyHexadecimalCharacters(): void
|
||||
{
|
||||
$converter = new BigNumberConverter();
|
||||
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('$hex must contain only hexadecimal characters');
|
||||
$this->expectExceptionMessage('"." is not a valid character in base 16');
|
||||
|
||||
$converter->fromHex('123.34');
|
||||
}
|
||||
@@ -69,7 +25,10 @@ class BigNumberConverterTest extends TestCase
|
||||
$converter = new BigNumberConverter();
|
||||
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('$number must contain only digits');
|
||||
$this->expectExceptionMessage(
|
||||
'Value must be a signed integer or a string containing only digits '
|
||||
. '0-9 and, optionally, a sign (+ or -)'
|
||||
);
|
||||
|
||||
$converter->toHex('123.34');
|
||||
}
|
||||
|
||||
@@ -4,26 +4,31 @@ declare(strict_types=1);
|
||||
|
||||
namespace Ramsey\Uuid\Test\Converter\Time;
|
||||
|
||||
use AspectMock\Test as AspectMock;
|
||||
use Brick\Math\BigInteger;
|
||||
use Ramsey\Uuid\Converter\Time\BigNumberTimeConverter;
|
||||
use Ramsey\Uuid\Exception\InvalidArgumentException;
|
||||
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
|
||||
use Ramsey\Uuid\Test\TestCase;
|
||||
|
||||
class BigNumberTimeConverterTest extends TestCase
|
||||
{
|
||||
public function testCalculateTimeReturnsArrayOfTimeSegments(): void
|
||||
{
|
||||
$this->skip64BitTest();
|
||||
$seconds = BigInteger::of(5);
|
||||
$microSeconds = BigInteger::of(3);
|
||||
|
||||
$seconds = 5;
|
||||
$microSeconds = 3;
|
||||
$calculatedTime = ($seconds * 10000000) + ($microSeconds * 10) + 0x01b21dd213814000;
|
||||
$calculatedTime = BigInteger::zero()
|
||||
->plus($seconds->multipliedBy(10000000))
|
||||
->plus($microSeconds->multipliedBy(10))
|
||||
->plus(BigInteger::fromBase('01b21dd213814000', 16));
|
||||
|
||||
$maskLow = BigInteger::fromBase('ffffffff', 16);
|
||||
$maskMid = BigInteger::fromBase('ffff', 16);
|
||||
$maskHi = BigInteger::fromBase('0fff', 16);
|
||||
|
||||
$expectedArray = [
|
||||
'low' => sprintf('%08x', $calculatedTime & 0xffffffff),
|
||||
'mid' => sprintf('%04x', ($calculatedTime >> 32) & 0xffff),
|
||||
'hi' => sprintf('%04x', ($calculatedTime >> 48) & 0x0fff),
|
||||
'low' => sprintf('%08s', $calculatedTime->and($maskLow)->toBase(16)),
|
||||
'mid' => sprintf('%04s', $calculatedTime->shiftedRight(32)->and($maskMid)->toBase(16)),
|
||||
'hi' => sprintf('%04s', $calculatedTime->shiftedRight(48)->and($maskHi)->toBase(16)),
|
||||
];
|
||||
|
||||
$converter = new BigNumberTimeConverter();
|
||||
@@ -34,62 +39,21 @@ class BigNumberTimeConverterTest extends TestCase
|
||||
|
||||
public function testConvertTime(): void
|
||||
{
|
||||
$this->skip64BitTest();
|
||||
|
||||
$converter = new BigNumberTimeConverter();
|
||||
$returned = $converter->convertTime('135606608744910000');
|
||||
|
||||
$this->assertSame('1341368074', $returned);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
public function testCalculateTimeThrowsExceptionWhenGmpExtensionNotPresent(): void
|
||||
{
|
||||
$classExists = AspectMock::func(
|
||||
'Ramsey\Uuid\Converter',
|
||||
'class_exists',
|
||||
false
|
||||
);
|
||||
|
||||
$converter = new BigNumberTimeConverter();
|
||||
|
||||
$this->expectException(UnsatisfiedDependencyException::class);
|
||||
$this->expectExceptionMessage('moontoast/math must be present to use this converter');
|
||||
|
||||
$converter->calculateTime('1234', '5678');
|
||||
$classExists->verifyInvokedOnce(['Moontoast\Math\BigNumber']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
public function testConvertTimeThrowsExceptionWhenGmpExtensionNotPresent(): void
|
||||
{
|
||||
$classExists = AspectMock::func(
|
||||
'Ramsey\Uuid\Converter',
|
||||
'class_exists',
|
||||
false
|
||||
);
|
||||
|
||||
$converter = new BigNumberTimeConverter();
|
||||
|
||||
$this->expectException(UnsatisfiedDependencyException::class);
|
||||
$this->expectExceptionMessage('moontoast/math must be present to use this converter');
|
||||
|
||||
$converter->convertTime('1234');
|
||||
$classExists->verifyInvokedOnce(['Moontoast\Math\BigNumber']);
|
||||
}
|
||||
|
||||
public function testCalculateTimeThrowsExceptionWhenSecondsIsNotOnlyDigits(): void
|
||||
{
|
||||
$converter = new BigNumberTimeConverter();
|
||||
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('$seconds must contain only digits');
|
||||
$this->expectExceptionMessage(
|
||||
'Value must be a signed integer or a string containing only digits '
|
||||
. '0-9 and, optionally, a sign (+ or -)'
|
||||
);
|
||||
|
||||
$converter->calculateTime('12.34', '5678');
|
||||
}
|
||||
@@ -99,7 +63,10 @@ class BigNumberTimeConverterTest extends TestCase
|
||||
$converter = new BigNumberTimeConverter();
|
||||
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('$microSeconds must contain only digits');
|
||||
$this->expectExceptionMessage(
|
||||
'Value must be a signed integer or a string containing only digits '
|
||||
. '0-9 and, optionally, a sign (+ or -)'
|
||||
);
|
||||
|
||||
$converter->calculateTime('1234', '56.78');
|
||||
}
|
||||
@@ -109,7 +76,10 @@ class BigNumberTimeConverterTest extends TestCase
|
||||
$converter = new BigNumberTimeConverter();
|
||||
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('$timestamp must contain only digits');
|
||||
$this->expectExceptionMessage(
|
||||
'Value must be a signed integer or a string containing only digits '
|
||||
. '0-9 and, optionally, a sign (+ or -)'
|
||||
);
|
||||
|
||||
$converter->convertTime('1234.56');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user