Upgrade framework

This commit is contained in:
2023-11-14 16:54:35 +01:00
parent 1648a5cd42
commit 4fcf6fffcc
10548 changed files with 693138 additions and 466698 deletions

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,191 +8,281 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid;
use DateTimeInterface;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface;
use Ramsey\Uuid\Generator\DefaultTimeGenerator;
use Ramsey\Uuid\Generator\NameGeneratorInterface;
use Ramsey\Uuid\Generator\RandomGeneratorInterface;
use Ramsey\Uuid\Generator\TimeGeneratorInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Generator\UnixTimeGenerator;
use Ramsey\Uuid\Lazy\LazyUuidFromString;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Provider\Time\FixedTimeProvider;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Type\Time;
use Ramsey\Uuid\Validator\ValidatorInterface;
use function bin2hex;
use function hex2bin;
use function pack;
use function str_pad;
use function strtolower;
use function substr;
use function substr_replace;
use function unpack;
use const STR_PAD_LEFT;
class UuidFactory implements UuidFactoryInterface
{
/**
* @var CodecInterface
*/
private $codec = null;
private CodecInterface $codec;
private DceSecurityGeneratorInterface $dceSecurityGenerator;
private NameGeneratorInterface $nameGenerator;
private NodeProviderInterface $nodeProvider;
private NumberConverterInterface $numberConverter;
private RandomGeneratorInterface $randomGenerator;
private TimeConverterInterface $timeConverter;
private TimeGeneratorInterface $timeGenerator;
private TimeGeneratorInterface $unixTimeGenerator;
private UuidBuilderInterface $uuidBuilder;
private ValidatorInterface $validator;
/**
* @var NodeProviderInterface
* @var bool whether the feature set was provided from outside, or we can
* operate under "default" assumptions
*/
private $nodeProvider = null;
private bool $isDefaultFeatureSet;
/**
* @var NumberConverterInterface
* @param FeatureSet|null $features A set of available features in the current environment
*/
private $numberConverter = null;
/**
* @var RandomGeneratorInterface
*/
private $randomGenerator = null;
/**
* @var TimeGeneratorInterface
*/
private $timeGenerator = null;
/**
* @var UuidBuilderInterface
*/
private $uuidBuilder = null;
/**
* Constructs a `UuidFactory` for creating `Ramsey\Uuid\UuidInterface` instances
*
* @param FeatureSet $features A set of features for use when creating UUIDs
*/
public function __construct(FeatureSet $features = null)
public function __construct(?FeatureSet $features = null)
{
$this->isDefaultFeatureSet = $features === null;
$features = $features ?: new FeatureSet();
$this->codec = $features->getCodec();
$this->dceSecurityGenerator = $features->getDceSecurityGenerator();
$this->nameGenerator = $features->getNameGenerator();
$this->nodeProvider = $features->getNodeProvider();
$this->numberConverter = $features->getNumberConverter();
$this->randomGenerator = $features->getRandomGenerator();
$this->timeConverter = $features->getTimeConverter();
$this->timeGenerator = $features->getTimeGenerator();
$this->uuidBuilder = $features->getBuilder();
$this->validator = $features->getValidator();
$this->unixTimeGenerator = $features->getUnixTimeGenerator();
}
/**
* Returns the UUID coder-decoder used by this factory
*
* @return CodecInterface
* Returns the codec used by this factory
*/
public function getCodec()
public function getCodec(): CodecInterface
{
return $this->codec;
}
/**
* Sets the UUID coder-decoder used by this factory
* Sets the codec to use for this factory
*
* @param CodecInterface $codec
* @param CodecInterface $codec A UUID encoder-decoder
*/
public function setCodec(CodecInterface $codec)
public function setCodec(CodecInterface $codec): void
{
$this->isDefaultFeatureSet = false;
$this->codec = $codec;
}
/**
* Returns the system node ID provider used by this factory
*
* @return NodeProviderInterface
* Returns the name generator used by this factory
*/
public function getNodeProvider()
public function getNameGenerator(): NameGeneratorInterface
{
return $this->nameGenerator;
}
/**
* Sets the name generator to use for this factory
*
* @param NameGeneratorInterface $nameGenerator A generator to generate
* binary data, based on a namespace and name
*/
public function setNameGenerator(NameGeneratorInterface $nameGenerator): void
{
$this->isDefaultFeatureSet = false;
$this->nameGenerator = $nameGenerator;
}
/**
* Returns the node provider used by this factory
*/
public function getNodeProvider(): NodeProviderInterface
{
return $this->nodeProvider;
}
/**
* Returns the random UUID generator used by this factory
*
* @return RandomGeneratorInterface
* Returns the random generator used by this factory
*/
public function getRandomGenerator()
public function getRandomGenerator(): RandomGeneratorInterface
{
return $this->randomGenerator;
}
/**
* Returns the time-based UUID generator used by this factory
*
* @return TimeGeneratorInterface
* Returns the time generator used by this factory
*/
public function getTimeGenerator()
public function getTimeGenerator(): TimeGeneratorInterface
{
return $this->timeGenerator;
}
/**
* Sets the time-based UUID generator this factory will use to generate version 1 UUIDs
* Sets the time generator to use for this factory
*
* @param TimeGeneratorInterface $generator
* @param TimeGeneratorInterface $generator A generator to generate binary
* data, based on the time
*/
public function setTimeGenerator(TimeGeneratorInterface $generator)
public function setTimeGenerator(TimeGeneratorInterface $generator): void
{
$this->isDefaultFeatureSet = false;
$this->timeGenerator = $generator;
}
/**
* Returns the number converter used by this factory
*
* @return NumberConverterInterface
* Returns the DCE Security generator used by this factory
*/
public function getNumberConverter()
public function getDceSecurityGenerator(): DceSecurityGeneratorInterface
{
return $this->dceSecurityGenerator;
}
/**
* Sets the DCE Security generator to use for this factory
*
* @param DceSecurityGeneratorInterface $generator A generator to generate
* binary data, based on a local domain and local identifier
*/
public function setDceSecurityGenerator(DceSecurityGeneratorInterface $generator): void
{
$this->isDefaultFeatureSet = false;
$this->dceSecurityGenerator = $generator;
}
/**
* Returns the number converter used by this factory
*/
public function getNumberConverter(): NumberConverterInterface
{
return $this->numberConverter;
}
/**
* Sets the random UUID generator this factory will use to generate version 4 UUIDs
* Sets the random generator to use for this factory
*
* @param RandomGeneratorInterface $generator
* @param RandomGeneratorInterface $generator A generator to generate binary
* data, based on some random input
*/
public function setRandomGenerator(RandomGeneratorInterface $generator)
public function setRandomGenerator(RandomGeneratorInterface $generator): void
{
$this->isDefaultFeatureSet = false;
$this->randomGenerator = $generator;
}
/**
* Sets the number converter this factory will use
* Sets the number converter to use for this factory
*
* @param NumberConverterInterface $converter
* @param NumberConverterInterface $converter A converter to use for working
* with large integers (i.e. integers greater than PHP_INT_MAX)
*/
public function setNumberConverter(NumberConverterInterface $converter)
public function setNumberConverter(NumberConverterInterface $converter): void
{
$this->isDefaultFeatureSet = false;
$this->numberConverter = $converter;
}
/**
* Returns the UUID builder this factory uses when creating `Uuid` instances
*
* @return UuidBuilderInterface $builder
* Returns the UUID builder used by this factory
*/
public function getUuidBuilder()
public function getUuidBuilder(): UuidBuilderInterface
{
return $this->uuidBuilder;
}
/**
* Sets the UUID builder this factory will use when creating `Uuid` instances
* Sets the UUID builder to use for this factory
*
* @param UuidBuilderInterface $builder
* @param UuidBuilderInterface $builder A builder for constructing instances
* of UuidInterface
*/
public function setUuidBuilder(UuidBuilderInterface $builder)
public function setUuidBuilder(UuidBuilderInterface $builder): void
{
$this->isDefaultFeatureSet = false;
$this->uuidBuilder = $builder;
}
public function fromBytes($bytes)
/**
* @psalm-mutation-free
*/
public function getValidator(): ValidatorInterface
{
return $this->validator;
}
/**
* Sets the validator to use for this factory
*
* @param ValidatorInterface $validator A validator to use for validating
* whether a string is a valid UUID
*/
public function setValidator(ValidatorInterface $validator): void
{
$this->isDefaultFeatureSet = false;
$this->validator = $validator;
}
/**
* @psalm-pure
*/
public function fromBytes(string $bytes): UuidInterface
{
return $this->codec->decodeBytes($bytes);
}
public function fromString($uuid)
/**
* @psalm-pure
*/
public function fromString(string $uuid): UuidInterface
{
$uuid = strtolower($uuid);
return $this->codec->decode($uuid);
}
public function fromInteger($integer)
/**
* @psalm-pure
*/
public function fromInteger(string $integer): UuidInterface
{
$hex = $this->numberConverter->toHex($integer);
$hex = str_pad($hex, 32, '0', STR_PAD_LEFT);
@@ -199,94 +290,224 @@ class UuidFactory implements UuidFactoryInterface
return $this->fromString($hex);
}
public function uuid1($node = null, $clockSeq = null)
public function fromDateTime(
DateTimeInterface $dateTime,
?Hexadecimal $node = null,
?int $clockSeq = null
): UuidInterface {
$timeProvider = new FixedTimeProvider(
new Time($dateTime->format('U'), $dateTime->format('u'))
);
$timeGenerator = new DefaultTimeGenerator(
$this->nodeProvider,
$this->timeConverter,
$timeProvider
);
$nodeHex = $node ? $node->toString() : null;
$bytes = $timeGenerator->generate($nodeHex, $clockSeq);
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME);
}
/**
* @psalm-pure
*/
public function fromHexadecimal(Hexadecimal $hex): UuidInterface
{
return $this->codec->decode($hex->__toString());
}
/**
* @inheritDoc
*/
public function uuid1($node = null, ?int $clockSeq = null): UuidInterface
{
$bytes = $this->timeGenerator->generate($node, $clockSeq);
$hex = bin2hex($bytes);
return $this->uuidFromHashedName($hex, 1);
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME);
}
public function uuid3($ns, $name)
public function uuid2(
int $localDomain,
?IntegerObject $localIdentifier = null,
?Hexadecimal $node = null,
?int $clockSeq = null
): UuidInterface {
$bytes = $this->dceSecurityGenerator->generate(
$localDomain,
$localIdentifier,
$node,
$clockSeq
);
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_DCE_SECURITY);
}
/**
* @inheritDoc
* @psalm-pure
*/
public function uuid3($ns, string $name): UuidInterface
{
return $this->uuidFromNsAndName($ns, $name, 3, 'md5');
return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_MD5, 'md5');
}
public function uuid4()
public function uuid4(): UuidInterface
{
$bytes = $this->randomGenerator->generate(16);
// When converting the bytes to hex, it turns into a 32-character
// hexadecimal string that looks a lot like an MD5 hash, so at this
// point, we can just pass it to uuidFromHashedName.
$hex = bin2hex($bytes);
return $this->uuidFromHashedName($hex, 4);
}
public function uuid5($ns, $name)
{
return $this->uuidFromNsAndName($ns, $name, 5, 'sha1');
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_RANDOM);
}
/**
* Returns a `Uuid`
*
* Uses the configured builder and codec and the provided array of hexadecimal
* value UUID fields to construct a `Uuid` object.
*
* @param array $fields An array of fields from which to construct a UUID;
* see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
* @return UuidInterface
* @inheritDoc
* @psalm-pure
*/
public function uuid(array $fields)
public function uuid5($ns, string $name): UuidInterface
{
return $this->uuidBuilder->build($this->codec, $fields);
return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_SHA1, 'sha1');
}
public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface
{
$nodeHex = $node ? $node->toString() : null;
$bytes = $this->timeGenerator->generate($nodeHex, $clockSeq);
// Rearrange the bytes, according to the UUID version 6 specification.
$v6 = $bytes[6] . $bytes[7] . $bytes[4] . $bytes[5]
. $bytes[0] . $bytes[1] . $bytes[2] . $bytes[3];
$v6 = bin2hex($v6);
// Drop the first four bits, while adding an empty four bits for the
// version field. This allows us to reconstruct the correct time from
// the bytes of this UUID.
$v6Bytes = hex2bin(substr($v6, 1, 12) . '0' . substr($v6, -3));
$v6Bytes .= substr($bytes, 8);
return $this->uuidFromBytesAndVersion($v6Bytes, Uuid::UUID_TYPE_REORDERED_TIME);
}
/**
* Returns a version 3 or 5 namespaced `Uuid`
* Returns a version 7 (Unix Epoch time) UUID
*
* @param string|UuidInterface $ns The UUID namespace to use
* @param string $name The string to hash together with the namespace
* @param DateTimeInterface|null $dateTime An optional date/time from which
* to create the version 7 UUID. If not provided, the UUID is generated
* using the current date/time.
*
* @return UuidInterface A UuidInterface instance that represents a
* version 7 UUID
*/
public function uuid7(?DateTimeInterface $dateTime = null): UuidInterface
{
assert($this->unixTimeGenerator instanceof UnixTimeGenerator);
$bytes = $this->unixTimeGenerator->generate(null, null, $dateTime);
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_UNIX_TIME);
}
/**
* Returns a version 8 (Custom) UUID
*
* The bytes provided may contain any value according to your application's
* needs. Be aware, however, that other applications may not understand the
* semantics of the value.
*
* @param string $bytes A 16-byte octet string. This is an open blob
* of data that you may fill with 128 bits of information. Be aware,
* however, bits 48 through 51 will be replaced with the UUID version
* field, and bits 64 and 65 will be replaced with the UUID variant. You
* MUST NOT rely on these bits for your application needs.
*
* @return UuidInterface A UuidInterface instance that represents a
* version 8 UUID
*/
public function uuid8(string $bytes): UuidInterface
{
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_CUSTOM);
}
/**
* Returns a Uuid created from the provided byte string
*
* Uses the configured builder and codec and the provided byte string to
* construct a Uuid object.
*
* @param string $bytes The byte string from which to construct a UUID
*
* @return UuidInterface An instance of UuidInterface, created from the
* provided bytes
*
* @psalm-pure
*/
public function uuid(string $bytes): UuidInterface
{
/** @psalm-suppress ImpurePropertyFetch */
return $this->uuidBuilder->build($this->codec, $bytes);
}
/**
* Returns a version 3 or 5 namespaced Uuid
*
* @param string|UuidInterface $ns The namespace (must be a valid UUID)
* @param string $name The name to hash together with the namespace
* @param int $version The version of UUID to create (3 or 5)
* @param string $hashFunction The hash function to use when hashing together
* the namespace and name
* @return UuidInterface
* @param string $hashAlgorithm The hashing algorithm to use when hashing
* together the namespace and name
*
* @return UuidInterface An instance of UuidInterface, created by hashing
* together the provided namespace and name
*
* @psalm-pure
*/
protected function uuidFromNsAndName($ns, $name, $version, $hashFunction)
{
private function uuidFromNsAndName(
UuidInterface | string $ns,
string $name,
int $version,
string $hashAlgorithm
): UuidInterface {
if (!($ns instanceof UuidInterface)) {
$ns = $this->codec->decode($ns);
$ns = $this->fromString($ns);
}
$hash = call_user_func($hashFunction, ($ns->getBytes() . $name));
$bytes = $this->nameGenerator->generate($ns, $name, $hashAlgorithm);
return $this->uuidFromHashedName($hash, $version);
return $this->uuidFromBytesAndVersion(substr($bytes, 0, 16), $version);
}
/**
* Returns a `Uuid` created from `$hash` with the version field set to `$version`
* and the variant field set for RFC 4122
* Returns an RFC 4122 variant Uuid, created from the provided bytes and version
*
* @param string $hash The hash to use when creating the UUID
* @param int $version The UUID version to set for this hash (1, 3, 4, or 5)
* @return UuidInterface
* @param string $bytes The byte string to convert to a UUID
* @param int $version The RFC 4122 version to apply to the UUID
*
* @return UuidInterface An instance of UuidInterface, created from the
* byte string and version
*
* @psalm-pure
*/
protected function uuidFromHashedName($hash, $version)
private function uuidFromBytesAndVersion(string $bytes, int $version): UuidInterface
{
$timeHi = BinaryUtils::applyVersion(substr($hash, 12, 4), $version);
$clockSeqHi = BinaryUtils::applyVariant(hexdec(substr($hash, 16, 2)));
/** @var array $unpackedTime */
$unpackedTime = unpack('n*', substr($bytes, 6, 2));
$timeHi = (int) $unpackedTime[1];
$timeHiAndVersion = pack('n*', BinaryUtils::applyVersion($timeHi, $version));
$fields = array(
'time_low' => substr($hash, 0, 8),
'time_mid' => substr($hash, 8, 4),
'time_hi_and_version' => str_pad(dechex($timeHi), 4, '0', STR_PAD_LEFT),
'clock_seq_hi_and_reserved' => str_pad(dechex($clockSeqHi), 2, '0', STR_PAD_LEFT),
'clock_seq_low' => substr($hash, 18, 2),
'node' => substr($hash, 20, 12),
);
/** @var array $unpackedClockSeq */
$unpackedClockSeq = unpack('n*', substr($bytes, 8, 2));
$clockSeqHi = (int) $unpackedClockSeq[1];
$clockSeqHiAndReserved = pack('n*', BinaryUtils::applyVariant($clockSeqHi));
return $this->uuid($fields);
$bytes = substr_replace($bytes, $timeHiAndVersion, 6, 2);
$bytes = substr_replace($bytes, $clockSeqHiAndReserved, 8, 2);
if ($this->isDefaultFeatureSet) {
return LazyUuidFromString::fromBytes($bytes);
}
/** @psalm-suppress ImpureVariable */
return $this->uuid($bytes);
}
}