From 323a608465c5e91cc1aa18a316bfb4bcd2bff754 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 22 Sep 2021 21:12:37 -0500
Subject: [PATCH 01/74] Add a GitHub workflow for the 3.x branch
---
.github/workflows/continuous-integration.yml | 108 +++++++++++++++++++
LICENSE | 2 +-
composer.json | 4 +-
tests/Builder/DefaultUuidBuilderTest.php | 4 +-
tests/Builder/DegradedUuidBuilderTest.php | 4 +-
5 files changed, 115 insertions(+), 7 deletions(-)
create mode 100644 .github/workflows/continuous-integration.yml
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
new file mode 100644
index 0000000..bc71be1
--- /dev/null
+++ b/.github/workflows/continuous-integration.yml
@@ -0,0 +1,108 @@
+# GitHub Actions Documentation: https://docs.github.com/en/actions
+
+name: "build"
+
+on: ["pull_request", "push"]
+
+env:
+ COMPOSER_ROOT_VERSION: "1.99.99"
+
+jobs:
+ coding-standards:
+ name: "Coding standards"
+ runs-on: "ubuntu-latest"
+ steps:
+ - name: "Checkout repository"
+ uses: "actions/checkout@v2"
+
+ - name: "Install PHP"
+ uses: "shivammathur/setup-php@v2"
+ with:
+ php-version: "latest"
+ extensions: bcmath, ctype, gmp, libsodium, uuid
+ coverage: "none"
+
+ - name: "Install dependencies (Composer)"
+ uses: "ramsey/composer-install@v1"
+
+ - name: "Check syntax (php-parallel-lint)"
+ run: "./vendor/bin/parallel-lint src tests --colors"
+
+ - name: "Check coding standards (PHP_CodeSniffer)"
+ run: "./vendor/bin/phpcs src tests --standard=psr2 -sp --colors"
+
+ code-coverage:
+ name: "Code coverage"
+ runs-on: "ubuntu-latest"
+ steps:
+ - name: "Checkout repository"
+ uses: "actions/checkout@v2"
+
+ - name: "Install PHP"
+ uses: "shivammathur/setup-php@v2"
+ with:
+ php-version: "latest"
+ extensions: bcmath, ctype, gmp, libsodium, uuid
+ coverage: "pcov"
+ ini-values: "memory_limit=-1"
+
+ - name: "Install dependencies (Composer)"
+ uses: "ramsey/composer-install@v1"
+
+ - name: "Run unit tests (PHPUnit)"
+ run: "./vendor/bin/phpunit --verbose --colors=always --coverage-text --coverage-clover build/logs/clover.xml"
+
+ - name: "Publish coverage report to Codecov"
+ uses: "codecov/codecov-action@v1"
+
+ unit-tests:
+ name: "Unit Tests"
+ runs-on: "ubuntu-latest"
+ continue-on-error: ${{ matrix.experimental }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ php-version:
+ - "5.4"
+ - "5.5"
+ - "5.6"
+ - "7.0"
+ - "7.1"
+ - "7.2"
+ - "7.3"
+ - "7.4"
+ # Commenting out the following until I can work out a solution for the
+ # development libraries I use, since many of them or their dependencies
+ # do not support PHP 8.
+ #
+ # - "8.0"
+ # experimental:
+ # - false
+ # include:
+ # - php-version: "8.1"
+ # experimental: true
+ # composer-options: "--ignore-platform-req=php"
+
+ steps:
+ - name: "Checkout repository"
+ uses: "actions/checkout@v2"
+
+ - name: "Install PHP"
+ uses: "shivammathur/setup-php@v2"
+ with:
+ php-version: "${{ matrix.php-version }}"
+ extensions: bcmath, ctype, gmp, libsodium, uuid
+ coverage: "none"
+ ini-values: "memory_limit=-1"
+
+ - name: "Create the logs directory"
+ run: "mkdir -p build/logs"
+
+ - name: "Install dependencies (Composer)"
+ uses: "ramsey/composer-install@v1"
+ with:
+ composer-options: "${{ matrix.composer-options }}"
+
+ - name: "Run unit tests (PHPUnit)"
+ run: "./vendor/bin/phpunit --verbose --colors=always --no-coverage"
diff --git a/LICENSE b/LICENSE
index b2aa4b5..1db0ef8 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2012-2020 Ben Ramsey
+Copyright (c) 2012-2021 Ben Ramsey
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/composer.json b/composer.json
index 62ece07..8baf11d 100644
--- a/composer.json
+++ b/composer.json
@@ -30,12 +30,12 @@
"codeception/aspect-mock": "^1 | ^2",
"doctrine/annotations": "^1.2",
"goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1",
- "jakub-onderka/php-parallel-lint": "^1",
"mockery/mockery": "^0.9.11 | ^1",
"moontoast/math": "^1.1",
"paragonie/random-lib": "^2",
"php-mock/php-mock-phpunit": "^0.3 | ^1.1",
- "phpunit/phpunit": "^4.8 | ^5.4 | ^6.5",
+ "php-parallel-lint/php-parallel-lint": "^1.3",
+ "phpunit/phpunit": ">=4.8.36",
"squizlabs/php_codesniffer": "^3.5"
},
"suggest": {
diff --git a/tests/Builder/DefaultUuidBuilderTest.php b/tests/Builder/DefaultUuidBuilderTest.php
index 125b497..b8bd593 100644
--- a/tests/Builder/DefaultUuidBuilderTest.php
+++ b/tests/Builder/DefaultUuidBuilderTest.php
@@ -2,15 +2,15 @@
namespace Ramsey\Uuid\Test\Builder;
-use PHPUnit_Framework_TestCase;
use Ramsey\Uuid\Builder\DefaultUuidBuilder;
+use Ramsey\Uuid\Test\TestCase;
/**
* Class DefaultUuidBuilderTest
* @package Ramsey\Uuid\Test\Builder
* @covers Ramsey\Uuid\Builder\DefaultUuidBuilder
*/
-class DefaultUuidBuilderTest extends PHPUnit_Framework_TestCase
+class DefaultUuidBuilderTest extends TestCase
{
public function testBuildCreatesUuid()
diff --git a/tests/Builder/DegradedUuidBuilderTest.php b/tests/Builder/DegradedUuidBuilderTest.php
index ce017e2..0ab682d 100644
--- a/tests/Builder/DegradedUuidBuilderTest.php
+++ b/tests/Builder/DegradedUuidBuilderTest.php
@@ -2,15 +2,15 @@
namespace Ramsey\Uuid\Test\Builder;
-use PHPUnit_Framework_TestCase;
use Ramsey\Uuid\Builder\DegradedUuidBuilder;
+use Ramsey\Uuid\Test\TestCase;
/**
* Class DegradedUuidBuilderTest
* @package Ramsey\Uuid\Test\Builder
* @covers Ramsey\Uuid\Builder\DegradedUuidBuilder
*/
-class DegradedUuidBuilderTest extends PHPUnit_Framework_TestCase
+class DegradedUuidBuilderTest extends TestCase
{
public function testBuildCreatesUuid()
From 1a7ec4a2d1c3a432c13c9ad55832ccdc27449d21 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 22 Sep 2021 21:15:13 -0500
Subject: [PATCH 02/74] Run coding standards and coverage on PHP 7.4
---
.github/workflows/continuous-integration.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index bc71be1..33f202a 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -18,7 +18,7 @@ jobs:
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
- php-version: "latest"
+ php-version: "7.4" # Unable to support 8 right now
extensions: bcmath, ctype, gmp, libsodium, uuid
coverage: "none"
@@ -41,7 +41,7 @@ jobs:
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
- php-version: "latest"
+ php-version: "7.4" # Unable to support 8 right now
extensions: bcmath, ctype, gmp, libsodium, uuid
coverage: "pcov"
ini-values: "memory_limit=-1"
From 64da73f96c77344dfabced7180a7260d3b2a8141 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 22 Sep 2021 21:16:15 -0500
Subject: [PATCH 03/74] Comment out continue-on-error for the unit tests build
---
.github/workflows/continuous-integration.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 33f202a..4bc38a6 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -58,7 +58,7 @@ jobs:
unit-tests:
name: "Unit Tests"
runs-on: "ubuntu-latest"
- continue-on-error: ${{ matrix.experimental }}
+ # continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
From 900324c01368334f8f450e63845fde99c630d42a Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 22 Sep 2021 21:27:27 -0500
Subject: [PATCH 04/74] Install dependencies for PECL extensions
---
.github/workflows/continuous-integration.yml | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 4bc38a6..848bfec 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -19,7 +19,6 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "7.4" # Unable to support 8 right now
- extensions: bcmath, ctype, gmp, libsodium, uuid
coverage: "none"
- name: "Install dependencies (Composer)"
@@ -38,6 +37,11 @@ jobs:
- name: "Checkout repository"
uses: "actions/checkout@v2"
+ - name: "Install dependencies (apt)"
+ run: |
+ sudo apt-get update
+ sudo apt-get -y install bsdmainutils libsodium-dev uuid-dev
+
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
@@ -88,6 +92,11 @@ jobs:
- name: "Checkout repository"
uses: "actions/checkout@v2"
+ - name: "Install dependencies (apt)"
+ run: |
+ sudo apt-get update
+ sudo apt-get -y install bsdmainutils libsodium-dev uuid-dev
+
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
From 1744aa802363286cd694ef8a9c3ce2060c536878 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 22 Sep 2021 21:31:54 -0500
Subject: [PATCH 05/74] Use sodium instead of libsodium
---
.github/workflows/continuous-integration.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 848bfec..ede696f 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -101,7 +101,7 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
- extensions: bcmath, ctype, gmp, libsodium, uuid
+ extensions: bcmath, ctype, gmp, sodium, uuid
coverage: "none"
ini-values: "memory_limit=-1"
From 1c50f77b065d3c47581a2a1f2d846c25d8d31af5 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 22 Sep 2021 21:41:22 -0500
Subject: [PATCH 06/74] See if we can get extensions install on PHP 5
---
.github/workflows/continuous-integration.yml | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index ede696f..58adb8d 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -46,7 +46,7 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "7.4" # Unable to support 8 right now
- extensions: bcmath, ctype, gmp, libsodium, uuid
+ extensions: "bcmath, ctype, gmp, sodium, uuid"
coverage: "pcov"
ini-values: "memory_limit=-1"
@@ -83,10 +83,16 @@ jobs:
# - "8.0"
# experimental:
# - false
- # include:
+ include:
# - php-version: "8.1"
# experimental: true
# composer-options: "--ignore-platform-req=php"
+ - php-version: "5.4"
+ extensions: ", libsodium-1.0.7, uuid-1.0.4"
+ - php-version: "5.5"
+ extensions: ", libsodium-1.0.7, uuid-1.0.4"
+ - php-version: "5.6"
+ extensions: ", libsodium-1.0.7, uuid-1.0.4"
steps:
- name: "Checkout repository"
@@ -101,7 +107,7 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
- extensions: bcmath, ctype, gmp, sodium, uuid
+ extensions: "bcmath, ctype, gmp, sodium, uuid ${{ matrix.extensions }}"
coverage: "none"
ini-values: "memory_limit=-1"
From 8d6c144a37fc7e18939fd1ccd1dd4e17aafb5f5d Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 22 Sep 2021 21:49:30 -0500
Subject: [PATCH 07/74] Remove Travis CI support files and configs
---
.travis.yml | 68 ----------------------
resources/docker/Dockerfile | 25 --------
resources/docker/build.sh | 10 ----
resources/docker/composer-install.sh | 17 ------
resources/scripts/cmd-proxy.sh | 25 --------
resources/scripts/php-coveralls.sh | 9 ---
resources/scripts/system-info.sh | 19 ------
resources/scripts/travis-before-install.sh | 15 -----
8 files changed, 188 deletions(-)
delete mode 100644 .travis.yml
delete mode 100644 resources/docker/Dockerfile
delete mode 100755 resources/docker/build.sh
delete mode 100755 resources/docker/composer-install.sh
delete mode 100755 resources/scripts/cmd-proxy.sh
delete mode 100755 resources/scripts/php-coveralls.sh
delete mode 100755 resources/scripts/system-info.sh
delete mode 100755 resources/scripts/travis-before-install.sh
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index e04cbc0..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-language: php
-os: linux
-
-services:
- - docker
-
-jobs:
- fast_finish: true
- include:
- - php: 5.4
- dist: trusty
- - php: 5.5
- dist: trusty
- - php: 5.6
- - php: 7.0
- - php: 7.1
- - php: 7.1
- arch: s390x
- - php: 7.2
- - php: 7.2
- arch: s390x
- - php: 7.2
- arch: arm64
- env: ARCH=arm32
- - php: 7.3
- - php: 7.3
- arch: s390x
- - php: 7.3
- arch: arm64
- env: ARCH=arm32
- - php: 7.4
- - php: 7.4
- arch: s390x
- - php: 7.4
- arch: arm64
- env: ARCH=arm32
- - php: nightly
- - php: nightly
- arch: s390x
- allow_failures:
- - php: nightly
-
-addons:
- apt:
- update: true
- packages:
- - bsdmainutils
- - libsodium-dev
- - uuid-dev
-
-before_install:
- - travis_retry ./resources/scripts/travis-before-install.sh
- - ./resources/scripts/cmd-proxy.sh ./resources/scripts/system-info.sh
-
-install:
- - travis_retry ./resources/scripts/cmd-proxy.sh composer require --no-update "php-coveralls/php-coveralls:^1 | ^2"
- - travis_retry ./resources/scripts/cmd-proxy.sh composer install --no-interaction --prefer-dist --no-progress --no-suggest
-
-before_script:
- - mkdir -p build/logs
-
-script:
- - ./resources/scripts/cmd-proxy.sh ./vendor/bin/parallel-lint src tests
- - ./resources/scripts/cmd-proxy.sh ./vendor/bin/phpcs src tests --standard=psr2 -sp --colors
- - travis_wait ./resources/scripts/cmd-proxy.sh ./vendor/bin/phpunit --verbose --coverage-clover build/logs/clover.xml
-
-after_success:
- - travis_retry ./resources/scripts/php-coveralls.sh
diff --git a/resources/docker/Dockerfile b/resources/docker/Dockerfile
deleted file mode 100644
index 96aaf00..0000000
--- a/resources/docker/Dockerfile
+++ /dev/null
@@ -1,25 +0,0 @@
-ARG PHP_VERSION
-ARG ARCH
-
-FROM ${ARCH}/php:${PHP_VERSION}-cli-alpine
-
-RUN apk update \
- && apk add --virtual=builddeps autoconf g++ gcc libc6-compat make re2c \
- && apk add \
- git \
- gmp-dev \
- libsodium-dev \
- libzip-dev \
- unzip \
- util-linux-dev \
- && docker-php-ext-install -j$(nproc) bcmath gmp zip \
- && yes '' | pecl install libsodium-1.0.7 \
- && yes '' | pecl install uuid \
- && yes '' | pecl install xdebug \
- && docker-php-ext-enable libsodium uuid xdebug \
- && apk del builddeps
-
-COPY composer-install.sh /usr/local/bin/composer-install.sh
-RUN composer-install.sh \
- && mv composer.phar /usr/local/bin/composer \
- && rm /usr/local/bin/composer-install.sh
diff --git a/resources/docker/build.sh b/resources/docker/build.sh
deleted file mode 100755
index 8cb3029..0000000
--- a/resources/docker/build.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-PHP_VERSION=$1
-ARCH=$2
-
-docker build \
- --tag benramsey/ramsey-uuid:php-${PHP_VERSION}-${ARCH} \
- --build-arg PHP_VERSION=${PHP_VERSION} \
- --build-arg ARCH=${ARCH} \
- .
diff --git a/resources/docker/composer-install.sh b/resources/docker/composer-install.sh
deleted file mode 100755
index 89abc1a..0000000
--- a/resources/docker/composer-install.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh
-
-EXPECTED_SIGNATURE="$(curl --silent https://composer.github.io/installer.sig)"
-php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
-ACTUAL_SIGNATURE="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
-
-if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ]
-then
- >&2 echo 'ERROR: Invalid installer signature'
- rm composer-setup.php
- exit 1
-fi
-
-php composer-setup.php --quiet
-RESULT=$?
-rm composer-setup.php
-exit $RESULT
diff --git a/resources/scripts/cmd-proxy.sh b/resources/scripts/cmd-proxy.sh
deleted file mode 100755
index f44eb56..0000000
--- a/resources/scripts/cmd-proxy.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/sh
-#
-# This script uses the ARCH environment variable to determine whether to run
-# the commands through a 32-bit Docker container, for 32-bit testing. If the
-# ARCH is anything other than "arm32," then it simply executes the commands
-# on the local system, rather than in a container.
-
-php_version="${TRAVIS_PHP_VERSION:-$(php -r "echo phpversion();")}"
-
-dots_count=$(echo $php_version | awk -F"." '{print NF-1}')
-if [ $dots_count -ge 2 ]; then
- php_version="${php_version%.*}"
-fi
-
-architecture="${ARCH:-${TRAVIS_CPU_ARCH:-$(uname -m)}}"
-
-cmd_proxy=""
-
-if [ "${architecture}" = "arm32" ]; then
- image="benramsey/ramsey-uuid:php-${php_version}-arm32v7"
- volumes="-v ${PWD}:${PWD}"
- cmd_proxy="docker run --rm ${volumes} -w ${PWD} ${image}"
-fi
-
-$cmd_proxy "$@"
diff --git a/resources/scripts/php-coveralls.sh b/resources/scripts/php-coveralls.sh
deleted file mode 100755
index d194ff4..0000000
--- a/resources/scripts/php-coveralls.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ -f vendor/bin/php-coveralls ]; then
- php vendor/bin/php-coveralls -v
-else
- php vendor/bin/coveralls -v
-fi
diff --git a/resources/scripts/system-info.sh b/resources/scripts/system-info.sh
deleted file mode 100755
index af35a54..0000000
--- a/resources/scripts/system-info.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-endianness=$(printf I | hexdump -o | awk '{ print substr($2,6,1); exit}')
-
-endian="Big"
-if [ "${endianness}" = "1" ]; then
- endian="Little"
-fi
-
-echo
-echo "SYSTEM INFORMATION:"
-echo
-echo "$(uname -a)"
-echo
-echo "CPU mode: $(getconf LONG_BIT)-bit"
-echo "Endianness: ${endian}"
-echo
-php --version
-echo
diff --git a/resources/scripts/travis-before-install.sh b/resources/scripts/travis-before-install.sh
deleted file mode 100755
index 1612def..0000000
--- a/resources/scripts/travis-before-install.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-#
-# This script runs as part of the Travis CI before_install phase. If the ARCH
-# environment variable is set and has the value "arm32," then we exit early,
-# since we will use a pre-built Docker image to run commands instead.
-
-architecture=${ARCH:-${TRAVIS_CPU_ARCH:-$(uname -m)}}
-
-if [ "${architecture}" = "arm32" ]; then
- exit
-fi
-
-yes '' | pecl install -f libsodium-1.0.7
-yes '' | pecl install -f uuid-1.0.4
-composer self-update
From 372d084fe93e007db7090693c7becf60202352a1 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 22 Sep 2021 21:51:30 -0500
Subject: [PATCH 08/74] Add configuration for Codecov
---
.gitattributes | 3 +--
codecov.yml | 29 +++++++++++++++++++++++++++++
2 files changed, 30 insertions(+), 2 deletions(-)
create mode 100644 codecov.yml
diff --git a/.gitattributes b/.gitattributes
index a3066a5..ae09278 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,9 +1,8 @@
.gitattributes export-ignore
.github/ export-ignore
.gitignore export-ignore
-.travis.yml export-ignore
+codecov.yml export-ignore
docs/ export-ignore
phpstan.neon export-ignore
phpunit.xml.dist export-ignore
-resources/ export-ignore
tests/ export-ignore
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000..047a8a9
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,29 @@
+codecov:
+ require_ci_to_pass: yes
+
+coverage:
+ precision: 2
+ round: down
+ range: "70...100"
+ status:
+ project:
+ default:
+ target: auto
+ threshold: 0%
+ patch:
+ default:
+ target: auto
+ threshold: 0%
+
+parsers:
+ gcov:
+ branch_detection:
+ conditional: yes
+ loop: yes
+ method: no
+ macro: no
+
+comment:
+ layout: "reach,diff,flags,tree"
+ behavior: default
+ require_changes: false
From 1c5b9aa277ffdb85e94857e09e5d5fdddf5ab51c Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 22 Sep 2021 22:00:13 -0500
Subject: [PATCH 09/74] Set up pcov for coverage
---
.github/workflows/continuous-integration.yml | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 58adb8d..636502f 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -41,6 +41,7 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -y install bsdmainutils libsodium-dev uuid-dev
+ mkdir -p build/logs
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
@@ -53,6 +54,11 @@ jobs:
- name: "Install dependencies (Composer)"
uses: "ramsey/composer-install@v1"
+ - name: "Setup PCOV"
+ run: |
+ composer require pcov/clobber
+ vendor/bin/pcov clobber
+
- name: "Run unit tests (PHPUnit)"
run: "./vendor/bin/phpunit --verbose --colors=always --coverage-text --coverage-clover build/logs/clover.xml"
@@ -102,6 +108,7 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -y install bsdmainutils libsodium-dev uuid-dev
+ mkdir -p build/logs
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
@@ -111,9 +118,6 @@ jobs:
coverage: "none"
ini-values: "memory_limit=-1"
- - name: "Create the logs directory"
- run: "mkdir -p build/logs"
-
- name: "Install dependencies (Composer)"
uses: "ramsey/composer-install@v1"
with:
From 3b166cd5e734ddfb95d9502066b926f7348b3665 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 23 Sep 2021 11:19:52 -0500
Subject: [PATCH 10/74] Update README badges
---
README.md | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index 95d4c21..28fa5c9 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# ramsey/uuid
+*IMPORTANT: This is the 3.x series. Please upgrade to the 4.x series.*
+
*NOTICE: Formerly known as `rhumsaa/uuid`, The package and namespace names have
changed to `ramsey/uuid` and `Ramsey\Uuid`, respectively.*
@@ -9,7 +11,6 @@ changed to `ramsey/uuid` and `Ramsey\Uuid`, respectively.*
[![PHP Version][badge-php]][php]
[![Build Status][badge-build]][build]
[![Coverage Status][badge-coverage]][coverage]
-[![Total Downloads][badge-downloads]][downloads]
ramsey/uuid is a PHP 5.4+ library for generating and working with
[RFC 4122][rfc4122] version 1, 3, 4, and 5 universally unique identifiers
@@ -171,15 +172,13 @@ information.
[badge-source]: https://img.shields.io/badge/source-ramsey/uuid-blue.svg?style=flat-square
[badge-release]: https://img.shields.io/packagist/v/ramsey/uuid.svg?style=flat-square&label=release
[badge-license]: https://img.shields.io/packagist/l/ramsey/uuid.svg?style=flat-square
-[badge-php]: https://img.shields.io/packagist/php-v/ramsey/uuid.svg?style=flat-square
-[badge-build]: https://img.shields.io/travis/ramsey/uuid/master.svg?style=flat-square
-[badge-coverage]: https://img.shields.io/coveralls/github/ramsey/uuid/master.svg?style=flat-square
-[badge-downloads]: https://img.shields.io/packagist/dt/ramsey/uuid.svg?style=flat-square&colorB=mediumvioletred
+[badge-php]: https://img.shields.io/packagist/php-v/ramsey/uuid/3.x-dev.svg?style=flat-square
+[badge-build]: https://img.shields.io/github/workflow/status/ramsey/uuid/build/3.x.svg?logo=github&style=flat-square
+[badge-coverage]: https://img.shields.io/codecov/c/gh/ramsey/uuid/3.x.svg?style=flat-square&logo=codecov
[source]: https://github.com/ramsey/uuid
[release]: https://packagist.org/packages/ramsey/uuid
[license]: https://github.com/ramsey/uuid/blob/master/LICENSE
[php]: https://php.net
-[build]: https://travis-ci.org/ramsey/uuid
-[coverage]: https://coveralls.io/github/ramsey/uuid?branch=master
-[downloads]: https://packagist.org/packages/ramsey/uuid
+[build]: https://github.com/ramsey/uuid/actions/workflows/continuous-integration.yml?query=branch%3A3.x
+[coverage]: https://app.codecov.io/gh/ramsey/uuid/branch/3.x
From d10c09b1667848380c4c5b03134ad43be4147ef8 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 23 Sep 2021 11:47:19 -0500
Subject: [PATCH 11/74] Restrict codeception/aspect-mock from going above 2.3.2
Refer to https://github.com/Codeception/AspectMock/issues/185
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 8baf11d..13ae4cb 100644
--- a/composer.json
+++ b/composer.json
@@ -27,7 +27,7 @@
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
- "codeception/aspect-mock": "^1 | ^2",
+ "codeception/aspect-mock": "^1 | >=2.0.0 <=2.3.2",
"doctrine/annotations": "^1.2",
"goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1",
"mockery/mockery": "^0.9.11 | ^1",
From fe0bc83c60858410774f08645b406cb9c375c5c6 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 23 Sep 2021 12:20:20 -0500
Subject: [PATCH 12/74] Revert "Restrict codeception/aspect-mock from going
above 2.3.2"
This reverts commit d10c09b1667848380c4c5b03134ad43be4147ef8.
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 13ae4cb..8baf11d 100644
--- a/composer.json
+++ b/composer.json
@@ -27,7 +27,7 @@
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
- "codeception/aspect-mock": "^1 | >=2.0.0 <=2.3.2",
+ "codeception/aspect-mock": "^1 | ^2",
"doctrine/annotations": "^1.2",
"goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1",
"mockery/mockery": "^0.9.11 | ^1",
From e2ec78e3d9b498bc1da616a0112732bb2e4adfa4 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 23 Sep 2021 12:22:32 -0500
Subject: [PATCH 13/74] Attempt to pin a few versions to get tests passing on
PHP 7.0
See https://github.com/Codeception/AspectMock/issues/185
---
composer.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 8baf11d..0ee4144 100644
--- a/composer.json
+++ b/composer.json
@@ -29,9 +29,10 @@
"require-dev": {
"codeception/aspect-mock": "^1 | ^2",
"doctrine/annotations": "^1.2",
- "goaop/framework": "1.0.0-alpha.2 | ^1 | ^2.1",
+ "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
"mockery/mockery": "^0.9.11 | ^1",
"moontoast/math": "^1.1",
+ "nikic/php-parser": "<=4.5.0",
"paragonie/random-lib": "^2",
"php-mock/php-mock-phpunit": "^0.3 | ^1.1",
"php-parallel-lint/php-parallel-lint": "^1.3",
From c9ed6dd82fb46dc4d54bc42e87e36f92a41922a4 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 23 Sep 2021 13:58:48 -0500
Subject: [PATCH 14/74] Prepare tests for running on PHP 8
---
.github/workflows/continuous-integration.yml | 18 +-
composer.json | 5 +-
tests/Codec/GuidStringCodecTest.php | 8 +-
tests/Codec/OrderedTimeCodecTest.php | 10 +-
tests/Codec/StringCodecTest.php | 12 +-
.../Number/DegradedNumberConverterTest.php | 10 +-
tests/Encoder/TimestampFirstCombCodecTest.php | 3 +-
tests/Encoder/TimestampLastCombCodecTest.php | 3 +-
tests/ExpectedBehaviorTest.php | 22 +--
tests/FunctionsTest.php | 8 +-
tests/Generator/CombGeneratorTest.php | 9 +-
tests/Generator/DefaultTimeGeneratorTest.php | 14 +-
tests/Generator/OpenSslGeneratorTest.php | 2 +
.../Generator/PeclUuidRandomGeneratorTest.php | 4 +
tests/Generator/PeclUuidTimeGeneratorTest.php | 4 +
tests/Generator/RandomBytesGeneratorTest.php | 2 +
tests/Generator/RandomLibAdapterTest.php | 11 +-
tests/Generator/SodiumRandomGeneratorTest.php | 2 +-
.../Provider/Node/RandomNodeProviderTest.php | 10 +-
.../Provider/Node/SystemNodeProviderTest.php | 15 ++
tests/Provider/Time/FixedTimeProviderTest.php | 2 +-
.../Provider/Time/SystemTimeProviderTest.php | 1 +
tests/TestCase.php | 14 +-
tests/UuidTest.php | 155 ++++++++----------
tests/bootstrap.php | 14 +-
25 files changed, 189 insertions(+), 169 deletions(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 636502f..b34ca20 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -68,7 +68,7 @@ jobs:
unit-tests:
name: "Unit Tests"
runs-on: "ubuntu-latest"
- # continue-on-error: ${{ matrix.experimental }}
+ continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
@@ -82,17 +82,13 @@ jobs:
- "7.2"
- "7.3"
- "7.4"
- # Commenting out the following until I can work out a solution for the
- # development libraries I use, since many of them or their dependencies
- # do not support PHP 8.
- #
- # - "8.0"
- # experimental:
- # - false
+ - "8.0"
+ experimental:
+ - false
include:
- # - php-version: "8.1"
- # experimental: true
- # composer-options: "--ignore-platform-req=php"
+ - php-version: "8.1"
+ experimental: true
+ composer-options: "--ignore-platform-req=php"
- php-version: "5.4"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
- php-version: "5.5"
diff --git a/composer.json b/composer.json
index 0ee4144..cb69fca 100644
--- a/composer.json
+++ b/composer.json
@@ -34,10 +34,11 @@
"moontoast/math": "^1.1",
"nikic/php-parser": "<=4.5.0",
"paragonie/random-lib": "^2",
- "php-mock/php-mock-phpunit": "^0.3 | ^1.1",
+ "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpunit/phpunit": ">=4.8.36",
- "squizlabs/php_codesniffer": "^3.5"
+ "squizlabs/php_codesniffer": "^3.5",
+ "yoast/phpunit-polyfills": "^1.0"
},
"suggest": {
"ext-ctype": "Provides support for PHP Ctype functions",
diff --git a/tests/Codec/GuidStringCodecTest.php b/tests/Codec/GuidStringCodecTest.php
index da69cda..feb80b9 100644
--- a/tests/Codec/GuidStringCodecTest.php
+++ b/tests/Codec/GuidStringCodecTest.php
@@ -22,9 +22,9 @@ class GuidStringCodecTest extends TestCase
/** @var array */
private $fields;
- protected function setUp()
+ protected function set_up()
{
- parent::setUp();
+ parent::set_up();
$this->builder = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
$this->uuid = $this->getMockBuilder('Ramsey\Uuid\UuidInterface')->getMock();
$this->fields = ['time_low' => '12345678',
@@ -35,9 +35,9 @@ class GuidStringCodecTest extends TestCase
'node' => '1234abcd4321'];
}
- protected function tearDown()
+ protected function tear_down()
{
- parent::tearDown();
+ parent::tear_down();
$this->builder = null;
$this->fields = null;
$this->uuid = null;
diff --git a/tests/Codec/OrderedTimeCodecTest.php b/tests/Codec/OrderedTimeCodecTest.php
index 33dae91..9fe51fb 100644
--- a/tests/Codec/OrderedTimeCodecTest.php
+++ b/tests/Codec/OrderedTimeCodecTest.php
@@ -26,9 +26,9 @@ class OrderedTimeCodecTest extends TestCase
/** @var string */
private $optimizedHex = '11d8eebc58e0a7d796690800200c9a66';
- protected function setUp()
+ protected function set_up()
{
- parent::setUp();
+ parent::set_up();
$this->builder = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
$this->uuid = $this->getMockBuilder('Ramsey\Uuid\UuidInterface')->getMock();
$this->fields = ['time_low' => '58e0a7d7',
@@ -39,9 +39,9 @@ class OrderedTimeCodecTest extends TestCase
'node' => '0800200c9a66'];
}
- protected function tearDown()
+ protected function tear_down()
{
- parent::tearDown();
+ parent::tear_down();
$this->builder = null;
$this->uuid = null;
$this->fields = null;
@@ -89,7 +89,7 @@ class OrderedTimeCodecTest extends TestCase
$string = '61';
$bytes = pack('H*', $string);
$codec = new OrderedTimeCodec($this->builder);
- $this->setExpectedException('InvalidArgumentException', '$bytes string should contain 16 characters.');
+ $this->expectException('InvalidArgumentException', '$bytes string should contain 16 characters.');
$codec->decodeBytes($bytes);
}
diff --git a/tests/Codec/StringCodecTest.php b/tests/Codec/StringCodecTest.php
index d86f0fb..a510191 100644
--- a/tests/Codec/StringCodecTest.php
+++ b/tests/Codec/StringCodecTest.php
@@ -24,9 +24,9 @@ class StringCodecTest extends TestCase
/** @var string */
private $uuidString = '12345678-1234-abcd-abef-1234abcd4321';
- protected function setUp()
+ protected function set_up()
{
- parent::setUp();
+ parent::set_up();
$this->builder = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
$this->uuid = $this->getMockBuilder('Ramsey\Uuid\UuidInterface')->getMock();
$this->fields = ['time_low' => '12345678',
@@ -37,9 +37,9 @@ class StringCodecTest extends TestCase
'node' => '1234abcd4321'];
}
- protected function tearDown()
+ protected function tear_down()
{
- parent::tearDown();
+ parent::tear_down();
$this->builder = null;
$this->uuid = null;
$this->fields = null;
@@ -95,7 +95,7 @@ class StringCodecTest extends TestCase
public function testDecodeThrowsExceptionOnInvalidUuid()
{
$string = 'invalid-uuid';
- $this->setExpectedException('\InvalidArgumentException');
+ $this->expectException('\InvalidArgumentException');
$codec = new StringCodec($this->builder);
$codec->decode($string);
}
@@ -115,7 +115,7 @@ class StringCodecTest extends TestCase
$string = '61';
$bytes = pack('H*', $string);
$codec = new StringCodec($this->builder);
- $this->setExpectedException('InvalidArgumentException', '$bytes string should contain 16 characters.');
+ $this->expectException('InvalidArgumentException', '$bytes string should contain 16 characters.');
$codec->decodeBytes($bytes);
}
diff --git a/tests/Converter/Number/DegradedNumberConverterTest.php b/tests/Converter/Number/DegradedNumberConverterTest.php
index 02a9b2d..9d6ad83 100644
--- a/tests/Converter/Number/DegradedNumberConverterTest.php
+++ b/tests/Converter/Number/DegradedNumberConverterTest.php
@@ -12,23 +12,21 @@ use Ramsey\Uuid\Converter\Number\DegradedNumberConverter;
*/
class DegradedNumberConverterTest extends TestCase
{
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testConvertingFromHexThrowsException()
{
$converter = new DegradedNumberConverter();
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$converter->fromHex('ffff');
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testConvertingToHexThrowsException()
{
$converter = new DegradedNumberConverter();
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$converter->toHex(0);
}
}
diff --git a/tests/Encoder/TimestampFirstCombCodecTest.php b/tests/Encoder/TimestampFirstCombCodecTest.php
index 248f6cb..911cf21 100644
--- a/tests/Encoder/TimestampFirstCombCodecTest.php
+++ b/tests/Encoder/TimestampFirstCombCodecTest.php
@@ -18,8 +18,9 @@ class TimestampFirstCombCodecTest extends TestCase
*/
private $builderMock;
- protected function setUp()
+ protected function set_up()
{
+ parent::set_up();
$this->builderMock = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
$this->codec = new TimestampFirstCombCodec($this->builderMock);
}
diff --git a/tests/Encoder/TimestampLastCombCodecTest.php b/tests/Encoder/TimestampLastCombCodecTest.php
index 266449b..7952a0a 100644
--- a/tests/Encoder/TimestampLastCombCodecTest.php
+++ b/tests/Encoder/TimestampLastCombCodecTest.php
@@ -18,8 +18,9 @@ class TimestampLastCombCodecTest extends TestCase
*/
private $builderMock;
- protected function setUp()
+ protected function set_up()
{
+ parent::set_up();
$this->builderMock = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
$this->codec = new TimestampLastCombCodec($this->builderMock);
}
diff --git a/tests/ExpectedBehaviorTest.php b/tests/ExpectedBehaviorTest.php
index 87de78f..733c1f1 100644
--- a/tests/ExpectedBehaviorTest.php
+++ b/tests/ExpectedBehaviorTest.php
@@ -32,27 +32,27 @@ class ExpectedBehaviorTest extends TestCase
$uuid = call_user_func_array(['Ramsey\Uuid\Uuid', $method], $args);
$this->assertInstanceOf('Ramsey\Uuid\UuidInterface', $uuid);
- $this->assertInternalType('int', $uuid->compareTo(Uuid::uuid1()));
+ $this->assertIsInt($uuid->compareTo(Uuid::uuid1()));
$this->assertNotSame(0, $uuid->compareTo(Uuid::uuid4()));
$this->assertSame(0, $uuid->compareTo(clone $uuid));
$this->assertFalse($uuid->equals(new stdClass()));
$this->assertTrue($uuid->equals(clone $uuid));
- $this->assertInternalType('string', $uuid->getBytes());
+ $this->assertIsString($uuid->getBytes());
$this->assertInstanceOf('Ramsey\Uuid\Converter\NumberConverterInterface', $uuid->getNumberConverter());
- $this->assertInternalType('string', $uuid->getHex());
- $this->assertInternalType('array', $uuid->getFieldsHex());
+ $this->assertIsString($uuid->getHex());
+ $this->assertIsArray($uuid->getFieldsHex());
$this->assertArrayHasKey('time_low', $uuid->getFieldsHex());
$this->assertArrayHasKey('time_mid', $uuid->getFieldsHex());
$this->assertArrayHasKey('time_hi_and_version', $uuid->getFieldsHex());
$this->assertArrayHasKey('clock_seq_hi_and_reserved', $uuid->getFieldsHex());
$this->assertArrayHasKey('clock_seq_low', $uuid->getFieldsHex());
$this->assertArrayHasKey('node', $uuid->getFieldsHex());
- $this->assertInternalType('string', $uuid->getTimeLowHex());
- $this->assertInternalType('string', $uuid->getTimeMidHex());
- $this->assertInternalType('string', $uuid->getTimeHiAndVersionHex());
- $this->assertInternalType('string', $uuid->getClockSeqHiAndReservedHex());
- $this->assertInternalType('string', $uuid->getClockSeqLowHex());
- $this->assertInternalType('string', $uuid->getNodeHex());
+ $this->assertIsString($uuid->getTimeLowHex());
+ $this->assertIsString($uuid->getTimeMidHex());
+ $this->assertIsString($uuid->getTimeHiAndVersionHex());
+ $this->assertIsString($uuid->getClockSeqHiAndReservedHex());
+ $this->assertIsString($uuid->getClockSeqLowHex());
+ $this->assertIsString($uuid->getNodeHex());
$this->assertSame($uuid->getFieldsHex()['time_low'], $uuid->getTimeLowHex());
$this->assertSame($uuid->getFieldsHex()['time_mid'], $uuid->getTimeMidHex());
$this->assertSame($uuid->getFieldsHex()['time_hi_and_version'], $uuid->getTimeHiAndVersionHex());
@@ -82,7 +82,7 @@ class ExpectedBehaviorTest extends TestCase
. $uuid->getFieldsHex()['node']
);
- $this->assertInternalType('string', $uuid->getUrn());
+ $this->assertIsString($uuid->getUrn());
$this->assertStringStartsWith('urn:uuid:', $uuid->getUrn());
$this->assertSame('urn:uuid:' . $uuid->getHex(), str_replace('-', '', $uuid->getUrn()));
$this->assertSame($uuid->getHex(), str_replace('-', '', $uuid->toString()));
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
index e8aaf46..1fc59fd 100644
--- a/tests/FunctionsTest.php
+++ b/tests/FunctionsTest.php
@@ -10,7 +10,7 @@ class FunctionsTest extends TestCase
{
$v1 = \Ramsey\Uuid\v1();
- $this->assertInternalType('string', $v1);
+ $this->assertIsString($v1);
$this->assertSame(Uuid::UUID_TYPE_TIME, Uuid::fromString($v1)->getVersion());
}
@@ -19,7 +19,7 @@ class FunctionsTest extends TestCase
$ns = Uuid::fromString(Uuid::NAMESPACE_URL);
$v3 = \Ramsey\Uuid\v3($ns, 'https://example.com/foo');
- $this->assertInternalType('string', $v3);
+ $this->assertIsString($v3);
$this->assertSame(Uuid::UUID_TYPE_HASH_MD5, Uuid::fromString($v3)->getVersion());
}
@@ -27,7 +27,7 @@ class FunctionsTest extends TestCase
{
$v4 = \Ramsey\Uuid\v4();
- $this->assertInternalType('string', $v4);
+ $this->assertIsString($v4);
$this->assertSame(Uuid::UUID_TYPE_RANDOM, Uuid::fromString($v4)->getVersion());
}
@@ -36,7 +36,7 @@ class FunctionsTest extends TestCase
$ns = Uuid::fromString(Uuid::NAMESPACE_URL);
$v5 = \Ramsey\Uuid\v5($ns, 'https://example.com/foo');
- $this->assertInternalType('string', $v5);
+ $this->assertIsString($v5);
$this->assertSame(Uuid::UUID_TYPE_HASH_SHA1, Uuid::fromString($v5)->getVersion());
}
}
diff --git a/tests/Generator/CombGeneratorTest.php b/tests/Generator/CombGeneratorTest.php
index 28bbd55..8f7ade0 100644
--- a/tests/Generator/CombGeneratorTest.php
+++ b/tests/Generator/CombGeneratorTest.php
@@ -59,7 +59,7 @@ class CombGeneratorTest extends TestCase
$generator = new CombGenerator($randomGenerator, $converter);
$returned = $generator->generate($length);
- $this->assertInternalType('string', $returned);
+ $this->assertIsString($returned);
$this->assertEquals($expected, $returned);
}
@@ -75,19 +75,16 @@ class CombGeneratorTest extends TestCase
*/
public function testGenerateWithLessThanTimestampBytesThrowsException($length)
{
- $this->setExpectedException('InvalidArgumentException');
+ $this->expectException('InvalidArgumentException');
$randomGenerator = $this->getMockBuilder('Ramsey\Uuid\Generator\RandomGeneratorInterface')->getMock();
$converter = $this->getMockBuilder('Ramsey\Uuid\Converter\NumberConverterInterface')->getMock();
$generator = new CombGenerator($randomGenerator, $converter);
$generator->generate($length);
}
- /**
- * PHP Unit converts the error to an exception so we can test it.
- */
public function testGenerateWithOddNumberOverTimestampBytesCausesError()
{
- $this->setExpectedException('PHPUnit_Framework_Error');
+ $this->expectError();
$randomGenerator = $this->getMockBuilder('Ramsey\Uuid\Generator\RandomGeneratorInterface')->getMock();
$converter = $this->getMockBuilder('Ramsey\Uuid\Converter\NumberConverterInterface')->getMock();
$generator = new CombGenerator($randomGenerator, $converter);
diff --git a/tests/Generator/DefaultTimeGeneratorTest.php b/tests/Generator/DefaultTimeGeneratorTest.php
index 3534297..51affa0 100644
--- a/tests/Generator/DefaultTimeGeneratorTest.php
+++ b/tests/Generator/DefaultTimeGeneratorTest.php
@@ -27,10 +27,9 @@ class DefaultTimeGeneratorTest extends TestCase
/** @var int */
private $clockSeq = 4066;
-
- protected function setUp()
+ protected function set_up()
{
- parent::setUp();
+ parent::set_up();
$this->timeProvider = $this->getMockBuilder('Ramsey\Uuid\Provider\TimeProviderInterface')->getMock();
$this->nodeProvider = $this->getMockBuilder('Ramsey\Uuid\Provider\NodeProviderInterface')->getMock();
$this->timeConverter = $this->getMockBuilder('Ramsey\Uuid\Converter\TimeConverterInterface')->getMock();
@@ -38,14 +37,12 @@ class DefaultTimeGeneratorTest extends TestCase
$this->calculatedTime = ["low" => "83cb98e0", "mid" => "98e0", "hi" => "03cb"];
}
- protected function tearDown()
+ protected function tear_down()
{
- parent::tearDown();
+ parent::tear_down();
$this->timeProvider = null;
$this->nodeProvider = null;
$this->timeConverter = null;
- Mockery::close();
- AspectMock::clean();
}
public function testGenerateUsesNodeProviderWhenNodeIsNull()
@@ -125,7 +122,7 @@ class DefaultTimeGeneratorTest extends TestCase
$this->timeConverter,
$this->timeProvider
);
- $defaultTimeGenerator->generate($this->nodeId, $this->clockSeq);
+ $this->assertIsString($defaultTimeGenerator->generate($this->nodeId, $this->clockSeq));
}
/**
@@ -170,6 +167,7 @@ class DefaultTimeGeneratorTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGenerateUsesRandomSequenceWhenClockSeqNull()
{
diff --git a/tests/Generator/OpenSslGeneratorTest.php b/tests/Generator/OpenSslGeneratorTest.php
index 33f28ae..f8edb22 100644
--- a/tests/Generator/OpenSslGeneratorTest.php
+++ b/tests/Generator/OpenSslGeneratorTest.php
@@ -26,6 +26,7 @@ class OpenSslGeneratorTest extends TestCase
* @dataProvider lengthAndHexDataProvider
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
* @param $length
* @param $hex
*/
@@ -43,6 +44,7 @@ class OpenSslGeneratorTest extends TestCase
* @dataProvider lengthAndHexDataProvider
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
* @param $length
* @param $hex
*/
diff --git a/tests/Generator/PeclUuidRandomGeneratorTest.php b/tests/Generator/PeclUuidRandomGeneratorTest.php
index 650a93c..9e5795e 100644
--- a/tests/Generator/PeclUuidRandomGeneratorTest.php
+++ b/tests/Generator/PeclUuidRandomGeneratorTest.php
@@ -17,6 +17,8 @@ class PeclUuidRandomGeneratorTest extends PeclUuidTestCase
* This test is just to check collaboration with the PECL UUID extension - not to check
* the correctness of the methods defined in that extension.
* So we are just checking that the UUID methods are called with the right parameters.
+ *
+ * @requires PHP < 8
*/
public function testGenerateCreatesUuidUsingPeclUuidMethods()
{
@@ -33,6 +35,8 @@ class PeclUuidRandomGeneratorTest extends PeclUuidTestCase
/**
* This test is for the return type of the generate method
* It ensures that the generate method returns whatever value uuid_parse returns.
+ *
+ * @requires PHP < 8
*/
public function testGenerateReturnsUuidString()
{
diff --git a/tests/Generator/PeclUuidTimeGeneratorTest.php b/tests/Generator/PeclUuidTimeGeneratorTest.php
index a3ed54a..28e42c0 100644
--- a/tests/Generator/PeclUuidTimeGeneratorTest.php
+++ b/tests/Generator/PeclUuidTimeGeneratorTest.php
@@ -16,6 +16,8 @@ class PeclUuidTimeGeneratorTest extends PeclUuidTestCase
* This test is just to check collaboration with the PECL UUID extension - not to check
* the correctness of the methods defined in that extension.
* So we are just checking that the UUID methods are called with the right parameters.
+ *
+ * @requires PHP < 8
*/
public function testGenerateCreatesUuidUsingPeclUuidMethods()
{
@@ -32,6 +34,8 @@ class PeclUuidTimeGeneratorTest extends PeclUuidTestCase
/**
* This test is for the return type of the generate method
* It ensures that the generate method returns whatever value uuid_parse returns.
+ *
+ * @requires PHP < 8
*/
public function testGenerateReturnsUuidString()
{
diff --git a/tests/Generator/RandomBytesGeneratorTest.php b/tests/Generator/RandomBytesGeneratorTest.php
index cd1092c..6721255 100644
--- a/tests/Generator/RandomBytesGeneratorTest.php
+++ b/tests/Generator/RandomBytesGeneratorTest.php
@@ -26,6 +26,7 @@ class RandomBytesGeneratorTest extends TestCase
* @dataProvider lengthAndHexDataProvider
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
* @param int $length
* @param string $hex
* @throws \Exception
@@ -44,6 +45,7 @@ class RandomBytesGeneratorTest extends TestCase
* @dataProvider lengthAndHexDataProvider
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
* @param int $length
* @param string $hex
* @throws \Exception
diff --git a/tests/Generator/RandomLibAdapterTest.php b/tests/Generator/RandomLibAdapterTest.php
index 9e0da77..254f2df 100644
--- a/tests/Generator/RandomLibAdapterTest.php
+++ b/tests/Generator/RandomLibAdapterTest.php
@@ -26,7 +26,11 @@ class RandomLibAdapterTest extends TestCase
$generator = $this->getMockBuilder('RandomLib\Generator')
->disableOriginalConstructor()
->getMock();
- new RandomLibAdapter($generator);
+
+ $this->assertInstanceOf(
+ 'Ramsey\Uuid\Generator\RandomGeneratorInterface',
+ new RandomLibAdapter($generator)
+ );
}
/**
@@ -40,7 +44,10 @@ class RandomLibAdapterTest extends TestCase
->once()
->getMock();
- new RandomLibAdapter();
+ $this->assertInstanceOf(
+ 'Ramsey\Uuid\Generator\RandomGeneratorInterface',
+ new RandomLibAdapter()
+ );
}
public function testGenerateUsesGenerator()
diff --git a/tests/Generator/SodiumRandomGeneratorTest.php b/tests/Generator/SodiumRandomGeneratorTest.php
index 7716d6d..1da2067 100644
--- a/tests/Generator/SodiumRandomGeneratorTest.php
+++ b/tests/Generator/SodiumRandomGeneratorTest.php
@@ -28,7 +28,7 @@ class SodiumRandomGeneratorTest extends TestCase
$bytes = $generator->generate(16);
- $this->assertInternalType('string', $bytes);
+ $this->assertIsString($bytes);
$this->assertEquals(16, strlen($bytes));
}
diff --git a/tests/Provider/Node/RandomNodeProviderTest.php b/tests/Provider/Node/RandomNodeProviderTest.php
index 647c93a..b390d23 100644
--- a/tests/Provider/Node/RandomNodeProviderTest.php
+++ b/tests/Provider/Node/RandomNodeProviderTest.php
@@ -8,15 +8,10 @@ use AspectMock\Test as AspectMock;
class RandomNodeProviderTest extends TestCase
{
- protected function tearDown()
- {
- parent::tearDown();
- AspectMock::clean();
- }
-
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGetNodeUsesRandomBytes()
{
@@ -31,6 +26,7 @@ class RandomNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGetNodeSetsMulticastBit()
{
@@ -48,6 +44,7 @@ class RandomNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGetNodeAlreadyHasMulticastBit()
{
@@ -66,6 +63,7 @@ class RandomNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGetNodeSetsMulticastBitForLowNodeValue()
{
diff --git a/tests/Provider/Node/SystemNodeProviderTest.php b/tests/Provider/Node/SystemNodeProviderTest.php
index 0cafa72..657f55e 100644
--- a/tests/Provider/Node/SystemNodeProviderTest.php
+++ b/tests/Provider/Node/SystemNodeProviderTest.php
@@ -50,6 +50,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*
* @dataProvider provideValidNetStatOutput
*
@@ -88,6 +89,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*
* @dataProvider provideInvalidNetStatOutput
*
@@ -119,6 +121,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*
* @dataProvider provideNotationalFormats
*
@@ -151,6 +154,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*
* @dataProvider provideInvalidNotationalFormats
*
@@ -182,6 +186,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGetNodeReturnsFirstMacAddressFound()
{
@@ -209,6 +214,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGetNodeReturnsFalseWhenNodeIsNotFound()
{
@@ -236,6 +242,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGetNodeWillNotExecuteSystemCallIfFailedFirstTime()
{
@@ -262,6 +269,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*
* @dataProvider provideCommandPerOs
*
@@ -306,6 +314,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGetNodeReturnsSameNodeUponSubsequentCalls()
{
@@ -334,6 +343,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testSubsequentCallsToGetNodeDoNotRecallIfconfig()
{
@@ -362,6 +372,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*
* @dataProvider provideCommandPerOs
*
@@ -420,6 +431,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testCallGetsysfsOnLinuxWhenGlobReturnsFalse()
{
@@ -453,6 +465,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testCallGetsysfsOnLinuxWhenGlobReturnsEmptyArray()
{
@@ -486,6 +499,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testCallGetsysfsOnLinuxWhenGlobFilesAreNotReadable()
{
@@ -522,6 +536,7 @@ class SystemNodeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testGetNodeReturnsFalseWhenPassthruIsDisabled()
{
diff --git a/tests/Provider/Time/FixedTimeProviderTest.php b/tests/Provider/Time/FixedTimeProviderTest.php
index 2f13943..5096675 100644
--- a/tests/Provider/Time/FixedTimeProviderTest.php
+++ b/tests/Provider/Time/FixedTimeProviderTest.php
@@ -10,7 +10,7 @@ class FixedTimeProviderTest extends TestCase
public function testConstructorRequiresSecAndUsec()
{
- $this->setExpectedException('InvalidArgumentException');
+ $this->expectException('InvalidArgumentException');
$provider = new FixedTimeProvider([]);
}
diff --git a/tests/Provider/Time/SystemTimeProviderTest.php b/tests/Provider/Time/SystemTimeProviderTest.php
index 8210efd..e1e5fbb 100644
--- a/tests/Provider/Time/SystemTimeProviderTest.php
+++ b/tests/Provider/Time/SystemTimeProviderTest.php
@@ -20,6 +20,7 @@ class SystemTimeProviderTest extends TestCase
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
+ * @requires PHP < 8
*/
public function testCurrentTimeUsesGettimeofday()
{
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 5a1cd05..e268c54 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -3,14 +3,18 @@ namespace Ramsey\Uuid\Test;
use AspectMock\Test as AspectMock;
use Mockery;
-use PHPUnit\Framework\TestCase as PhpUnitTestCase;
+use Yoast\PHPUnitPolyfills\TestCases\TestCase as YoastTestCase;
-class TestCase extends PhpUnitTestCase
+class TestCase extends YoastTestCase
{
- protected function tearDown()
+ protected function tear_down()
{
- parent::tearDown();
- AspectMock::clean();
+ parent::tear_down();
+
+ if (PHP_MAJOR_VERSION < 8) {
+ AspectMock::clean();
+ }
+
Mockery::close();
}
diff --git a/tests/UuidTest.php b/tests/UuidTest.php
index 4299fbc..f8085ed 100644
--- a/tests/UuidTest.php
+++ b/tests/UuidTest.php
@@ -14,8 +14,9 @@ use stdClass;
class UuidTest extends TestCase
{
- protected function setUp()
+ protected function set_up()
{
+ parent::set_up();
Uuid::setFactory(new UuidFactory());
}
@@ -80,21 +81,19 @@ class UuidTest extends TestCase
$this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString());
}
- /**
- * @expectedException Ramsey\Uuid\Exception\InvalidUuidStringException
- * @expectedExceptionMessage Invalid UUID string:
- */
public function testFromStringWithInvalidUuidString()
{
+ $this->expectException('Ramsey\Uuid\Exception\InvalidUuidStringException');
+ $this->expectExceptionMessage('Invalid UUID string:');
+
$uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21');
}
- /**
- * @expectedException Ramsey\Uuid\Exception\InvalidUuidStringException
- * @expectedExceptionMessage Invalid UUID string:
- */
public function testFromStringWithTrailingNewLine()
{
+ $this->expectException('Ramsey\Uuid\Exception\InvalidUuidStringException');
+ $this->expectExceptionMessage('Invalid UUID string:');
+
Uuid::fromString("d0d5f586-21d1-470c-8088-55c8857728dc\n");
}
@@ -225,9 +224,6 @@ class UuidTest extends TestCase
$this->assertSame('-12219292800', $uuid->getDateTime()->format('U'));
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testGetDateTimeThrownException()
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, true, true)));
@@ -237,15 +233,16 @@ class UuidTest extends TestCase
$this->assertInstanceOf('Ramsey\Uuid\DegradedUuid', $uuid);
$this->assertInstanceOf('Ramsey\Uuid\Converter\Number\DegradedNumberConverter', $uuid->getNumberConverter());
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$date = $uuid->getDateTime();
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsupportedOperationException
- * @expectedExceptionMessage Not a time-based UUID
- */
public function testGetDateTimeFromNonVersion1Uuid()
{
+ $this->expectException('Ramsey\Uuid\Exception\UnsupportedOperationException');
+ $this->expectExceptionMessage('Not a time-based UUID');
+
// Using a version 4 UUID to test
$uuid = Uuid::fromString('bf17b594-41f2-474f-bf70-4c90220f75de');
$date = $uuid->getDateTime();
@@ -271,14 +268,14 @@ class UuidTest extends TestCase
$this->assertEquals($fields, $uuid->getFields());
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testGetFields32Bit()
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, true)));
$uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66');
+
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$fields = $uuid->getFields();
}
@@ -311,14 +308,14 @@ class UuidTest extends TestCase
$this->assertEquals('11178224546741000806', $uuid->getLeastSignificantBits()->getValue());
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testGetLeastSignificantBitsException()
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true)));
$uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66');
+
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$bn = $uuid->getLeastSignificantBits();
}
@@ -341,14 +338,14 @@ class UuidTest extends TestCase
$this->assertEquals('18406084892941947361', $uuid->getMostSignificantBits()->getValue());
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testGetMostSignificantBitsException()
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true)));
$uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66');
+
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$bn = $uuid->getMostSignificantBits();
}
@@ -370,14 +367,14 @@ class UuidTest extends TestCase
$this->assertEquals(8796630719078, $uuid->getNode());
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testGetNode32Bit()
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, true)));
$uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66');
+
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$node = $uuid->getNode();
}
@@ -415,14 +412,14 @@ class UuidTest extends TestCase
$this->assertEquals(4285500592, $uuid->getTimeLow());
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testGetTimeLow32Bit()
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, true)));
$uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66');
+
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$timeLow = $uuid->getTimeLow();
}
@@ -478,36 +475,36 @@ class UuidTest extends TestCase
$this->assertEquals('00001540901e600', $uuid->getTimestampHex());
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsupportedOperationException
- * @expectedExceptionMessage Not a time-based UUID
- */
public function testGetTimestampFromNonVersion1Uuid()
{
// Using a version 4 UUID to test
$uuid = Uuid::fromString('bf17b594-41f2-474f-bf70-4c90220f75de');
+
+ $this->expectException('Ramsey\Uuid\Exception\UnsupportedOperationException');
+ $this->expectExceptionMessage('Not a time-based UUID');
+
$ts = $uuid->getTimestamp();
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsupportedOperationException
- * @expectedExceptionMessage Not a time-based UUID
- */
public function testGetTimestampHexFromNonVersion1Uuid()
{
// Using a version 4 UUID to test
$uuid = Uuid::fromString('bf17b594-41f2-474f-bf70-4c90220f75de');
+
+ $this->expectException('Ramsey\Uuid\Exception\UnsupportedOperationException');
+ $this->expectExceptionMessage('Not a time-based UUID');
+
$ts = $uuid->getTimestampHex();
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testGetTimestamp32Bit()
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, true)));
$uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66');
+
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$ts = $uuid->getTimestamp();
}
@@ -721,30 +718,27 @@ class UuidTest extends TestCase
}
}
- /**
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage Invalid node value
- */
public function testUuid1WithOutOfBoundsNode()
{
+ $this->expectException('InvalidArgumentException');
+ $this->expectExceptionMessage('Invalid node value');
+
$uuid = Uuid::uuid1(9223372036854775808);
}
- /**
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage Invalid node value
- */
public function testUuid1WithNonHexadecimalNode()
{
+ $this->expectException('InvalidArgumentException');
+ $this->expectExceptionMessage('Invalid node value');
+
$uuid = Uuid::uuid1('db77e160355g');
}
- /**
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage Invalid node value
- */
public function testUuid1WithNon48bitNumber()
{
+ $this->expectException('InvalidArgumentException');
+ $this->expectExceptionMessage('Invalid node value');
+
$uuid = Uuid::uuid1('db77e160355ef');
}
@@ -1349,13 +1343,12 @@ class UuidTest extends TestCase
}
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testCalculateUuidTimeThrownException()
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, true, true)));
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$uuid = Uuid::uuid1(0x00007ffffffe, 0x1669);
}
@@ -1515,19 +1508,17 @@ class UuidTest extends TestCase
$this->assertEquals($guid->toString(), $parsedGuid->toString());
}
- /**
- * @expectedException InvalidArgumentException
- */
public function testFromBytesArgumentTooShort()
{
+ $this->expectException('InvalidArgumentException');
+
Uuid::fromBytes('thisisveryshort');
}
- /**
- * @expectedException InvalidArgumentException
- */
public function testFromBytesArgumentTooLong()
{
+ $this->expectException('InvalidArgumentException');
+
Uuid::fromBytes('thisisabittoolong');
}
@@ -1865,32 +1856,32 @@ class UuidTest extends TestCase
if ($this->hasMoontoastMath()) {
$this->assertEquals($test['int'], (string)$uuid->getInteger());
}
- $this->assertEquals($test['fields'], $uuid->getFieldsHex());
- $this->assertEquals($test['fields']['time_low'], $uuid->getTimeLowHex());
- $this->assertEquals($test['fields']['time_mid'], $uuid->getTimeMidHex());
- $this->assertEquals($test['fields']['time_hi_and_version'], $uuid->getTimeHiAndVersionHex());
- $this->assertEquals($test['fields']['clock_seq_hi_and_reserved'], $uuid->getClockSeqHiAndReservedHex());
- $this->assertEquals($test['fields']['clock_seq_low'], $uuid->getClockSeqLowHex());
- $this->assertEquals($test['fields']['node'], $uuid->getNodeHex());
+ $this->assertTrue($test['fields'] == $uuid->getFieldsHex());
+ $this->assertTrue($test['fields']['time_low'] == $uuid->getTimeLowHex());
+ $this->assertTrue($test['fields']['time_mid'] == $uuid->getTimeMidHex());
+ $this->assertTrue($test['fields']['time_hi_and_version'] == $uuid->getTimeHiAndVersionHex());
+ $this->assertTrue($test['fields']['clock_seq_hi_and_reserved'] == $uuid->getClockSeqHiAndReservedHex());
+ $this->assertTrue($test['fields']['clock_seq_low'] == $uuid->getClockSeqLowHex());
+ $this->assertTrue($test['fields']['node'] == $uuid->getNodeHex());
$this->assertEquals($test['urn'], $uuid->getUrn());
if ($uuid->getVersion() == 1) {
- $this->assertEquals($test['time'], $uuid->getTimestampHex());
+ $this->assertTrue($test['time'] == $uuid->getTimestampHex());
}
- $this->assertEquals($test['clock_seq'], $uuid->getClockSequenceHex());
+ $this->assertTrue($test['clock_seq'] == $uuid->getClockSequenceHex());
$this->assertEquals($test['variant'], $uuid->getVariant());
$this->assertEquals($test['version'], $uuid->getVersion());
}
}
}
- /**
- * @expectedException Ramsey\Uuid\Exception\UnsatisfiedDependencyException
- */
public function testGetInteger()
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true)));
$uuid = Uuid::uuid1();
+
+ $this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+
$uuid->getInteger();
}
@@ -1912,12 +1903,11 @@ class UuidTest extends TestCase
$this->assertTrue($uuid->equals($unserializedUuid));
}
- /**
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage Invalid UUID string:
- */
public function testUuid3WithEmptyNamespace()
{
+ $this->expectException('InvalidArgumentException');
+ $this->expectExceptionMessage('Invalid UUID string:');
+
$uuid = Uuid::uuid3('', '');
}
@@ -1949,12 +1939,11 @@ class UuidTest extends TestCase
$this->assertEquals('19826852-5007-3022-a72a-212f66e9fac3', $uuid->toString());
}
- /**
- * @expectedException InvalidArgumentException
- * @expectedExceptionMessage Invalid UUID string:
- */
public function testUuid5WithEmptyNamespace()
{
+ $this->expectException('InvalidArgumentException');
+ $this->expectExceptionMessage('Invalid UUID string:');
+
$uuid = Uuid::uuid5('', '');
}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 22f23fa..052ea4f 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -8,9 +8,11 @@ use AspectMock\Kernel;
require_once __DIR__ . '/../vendor/autoload.php'; // composer autoload
require_once __DIR__ . '/phpstan-bootstrap.php';
-$kernel = Kernel::getInstance();
-$kernel->init([
- 'debug' => true,
- 'cacheDir' => sys_get_temp_dir(),
- 'includePaths' => [__DIR__ . '/../src']
-]);
+if (PHP_MAJOR_VERSION < 8) {
+ $kernel = Kernel::getInstance();
+ $kernel->init([
+ 'debug' => true,
+ 'cacheDir' => sys_get_temp_dir(),
+ 'includePaths' => [__DIR__ . '/../src']
+ ]);
+}
From 90031b396c4416f75ba1eed35ec7ff4cddc43ec1 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 23 Sep 2021 14:07:00 -0500
Subject: [PATCH 15/74] Fix coding standards and coverage issues
---
.github/workflows/continuous-integration.yml | 11 +++--------
tests/Codec/GuidStringCodecTest.php | 4 ++--
tests/Codec/OrderedTimeCodecTest.php | 4 ++--
tests/Codec/StringCodecTest.php | 4 ++--
tests/Encoder/TimestampFirstCombCodecTest.php | 2 +-
tests/Encoder/TimestampLastCombCodecTest.php | 2 +-
tests/Generator/DefaultTimeGeneratorTest.php | 4 ++--
tests/TestCase.php | 2 +-
tests/UuidTest.php | 2 +-
9 files changed, 15 insertions(+), 20 deletions(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index b34ca20..13bb062 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -54,11 +54,6 @@ jobs:
- name: "Install dependencies (Composer)"
uses: "ramsey/composer-install@v1"
- - name: "Setup PCOV"
- run: |
- composer require pcov/clobber
- vendor/bin/pcov clobber
-
- name: "Run unit tests (PHPUnit)"
run: "./vendor/bin/phpunit --verbose --colors=always --coverage-text --coverage-clover build/logs/clover.xml"
@@ -86,9 +81,9 @@ jobs:
experimental:
- false
include:
- - php-version: "8.1"
- experimental: true
- composer-options: "--ignore-platform-req=php"
+ #- php-version: "8.1"
+ # experimental: true
+ # composer-options: "--ignore-platform-req=php"
- php-version: "5.4"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
- php-version: "5.5"
diff --git a/tests/Codec/GuidStringCodecTest.php b/tests/Codec/GuidStringCodecTest.php
index feb80b9..a201457 100644
--- a/tests/Codec/GuidStringCodecTest.php
+++ b/tests/Codec/GuidStringCodecTest.php
@@ -22,7 +22,7 @@ class GuidStringCodecTest extends TestCase
/** @var array */
private $fields;
- protected function set_up()
+ protected function set_up() // phpcs:ignore
{
parent::set_up();
$this->builder = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
@@ -35,7 +35,7 @@ class GuidStringCodecTest extends TestCase
'node' => '1234abcd4321'];
}
- protected function tear_down()
+ protected function tear_down() // phpcs:ignore
{
parent::tear_down();
$this->builder = null;
diff --git a/tests/Codec/OrderedTimeCodecTest.php b/tests/Codec/OrderedTimeCodecTest.php
index 9fe51fb..6fd928e 100644
--- a/tests/Codec/OrderedTimeCodecTest.php
+++ b/tests/Codec/OrderedTimeCodecTest.php
@@ -26,7 +26,7 @@ class OrderedTimeCodecTest extends TestCase
/** @var string */
private $optimizedHex = '11d8eebc58e0a7d796690800200c9a66';
- protected function set_up()
+ protected function set_up() // phpcs:ignore
{
parent::set_up();
$this->builder = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
@@ -39,7 +39,7 @@ class OrderedTimeCodecTest extends TestCase
'node' => '0800200c9a66'];
}
- protected function tear_down()
+ protected function tear_down() // phpcs:ignore
{
parent::tear_down();
$this->builder = null;
diff --git a/tests/Codec/StringCodecTest.php b/tests/Codec/StringCodecTest.php
index a510191..8e5b9cf 100644
--- a/tests/Codec/StringCodecTest.php
+++ b/tests/Codec/StringCodecTest.php
@@ -24,7 +24,7 @@ class StringCodecTest extends TestCase
/** @var string */
private $uuidString = '12345678-1234-abcd-abef-1234abcd4321';
- protected function set_up()
+ protected function set_up() // phpcs:ignore
{
parent::set_up();
$this->builder = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
@@ -37,7 +37,7 @@ class StringCodecTest extends TestCase
'node' => '1234abcd4321'];
}
- protected function tear_down()
+ protected function tear_down() // phpcs:ignore
{
parent::tear_down();
$this->builder = null;
diff --git a/tests/Encoder/TimestampFirstCombCodecTest.php b/tests/Encoder/TimestampFirstCombCodecTest.php
index 911cf21..25d5cf4 100644
--- a/tests/Encoder/TimestampFirstCombCodecTest.php
+++ b/tests/Encoder/TimestampFirstCombCodecTest.php
@@ -18,7 +18,7 @@ class TimestampFirstCombCodecTest extends TestCase
*/
private $builderMock;
- protected function set_up()
+ protected function set_up() // phpcs:ignore
{
parent::set_up();
$this->builderMock = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
diff --git a/tests/Encoder/TimestampLastCombCodecTest.php b/tests/Encoder/TimestampLastCombCodecTest.php
index 7952a0a..f1801b9 100644
--- a/tests/Encoder/TimestampLastCombCodecTest.php
+++ b/tests/Encoder/TimestampLastCombCodecTest.php
@@ -18,7 +18,7 @@ class TimestampLastCombCodecTest extends TestCase
*/
private $builderMock;
- protected function set_up()
+ protected function set_up() // phpcs:ignore
{
parent::set_up();
$this->builderMock = $this->getMockBuilder('Ramsey\Uuid\Builder\UuidBuilderInterface')->getMock();
diff --git a/tests/Generator/DefaultTimeGeneratorTest.php b/tests/Generator/DefaultTimeGeneratorTest.php
index 51affa0..91521f0 100644
--- a/tests/Generator/DefaultTimeGeneratorTest.php
+++ b/tests/Generator/DefaultTimeGeneratorTest.php
@@ -27,7 +27,7 @@ class DefaultTimeGeneratorTest extends TestCase
/** @var int */
private $clockSeq = 4066;
- protected function set_up()
+ protected function set_up() // phpcs:ignore
{
parent::set_up();
$this->timeProvider = $this->getMockBuilder('Ramsey\Uuid\Provider\TimeProviderInterface')->getMock();
@@ -37,7 +37,7 @@ class DefaultTimeGeneratorTest extends TestCase
$this->calculatedTime = ["low" => "83cb98e0", "mid" => "98e0", "hi" => "03cb"];
}
- protected function tear_down()
+ protected function tear_down() // phpcs:ignore
{
parent::tear_down();
$this->timeProvider = null;
diff --git a/tests/TestCase.php b/tests/TestCase.php
index e268c54..9131266 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -7,7 +7,7 @@ use Yoast\PHPUnitPolyfills\TestCases\TestCase as YoastTestCase;
class TestCase extends YoastTestCase
{
- protected function tear_down()
+ protected function tear_down() // phpcs:ignore
{
parent::tear_down();
diff --git a/tests/UuidTest.php b/tests/UuidTest.php
index f8085ed..65594d4 100644
--- a/tests/UuidTest.php
+++ b/tests/UuidTest.php
@@ -14,7 +14,7 @@ use stdClass;
class UuidTest extends TestCase
{
- protected function set_up()
+ protected function set_up() // phpcs:ignore
{
parent::set_up();
Uuid::setFactory(new UuidFactory());
From 9264d240b8de1cca5f7761961781dc3bc9e938e7 Mon Sep 17 00:00:00 2001
From: Graham Campbell
Date: Thu, 23 Sep 2021 16:52:54 -0500
Subject: [PATCH 16/74] Support PHP 8.1
---
.github/workflows/continuous-integration.yml | 12 +++-----
src/Uuid.php | 29 ++++++++++++++++++++
2 files changed, 33 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 13bb062..fc18ae1 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -18,7 +18,7 @@ jobs:
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
- php-version: "7.4" # Unable to support 8 right now
+ php-version: "7.4"
coverage: "none"
- name: "Install dependencies (Composer)"
@@ -46,7 +46,7 @@ jobs:
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
- php-version: "7.4" # Unable to support 8 right now
+ php-version: "7.4"
extensions: "bcmath, ctype, gmp, sodium, uuid"
coverage: "pcov"
ini-values: "memory_limit=-1"
@@ -63,7 +63,6 @@ jobs:
unit-tests:
name: "Unit Tests"
runs-on: "ubuntu-latest"
- continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
@@ -78,18 +77,15 @@ jobs:
- "7.3"
- "7.4"
- "8.0"
- experimental:
- - false
include:
- #- php-version: "8.1"
- # experimental: true
- # composer-options: "--ignore-platform-req=php"
- php-version: "5.4"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
- php-version: "5.5"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
- php-version: "5.6"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
+ - php-version: "8.1"
+ composer-options: "--ignore-platform-req=php"
steps:
- name: "Checkout repository"
diff --git a/src/Uuid.php b/src/Uuid.php
index f2912b4..d51e0e1 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -22,6 +22,7 @@ use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Exception\InvalidUuidStringException;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
+use ReturnTypeWillChange;
/**
* Represents a universally unique identifier (UUID), according to RFC 4122.
@@ -224,11 +225,21 @@ class Uuid implements UuidInterface
* @return string
* @link http://php.net/manual/en/class.serializable.php
*/
+ #[ReturnTypeWillChange]
public function serialize()
{
return $this->toString();
}
+ /**
+ * @return array{string: string}
+ */
+ #[ReturnTypeWillChange]
+ public function __serialize()
+ {
+ return ['string' => $this->toString()];
+ }
+
/**
* Re-constructs the object from its serialized form.
*
@@ -236,6 +247,7 @@ class Uuid implements UuidInterface
* @link http://php.net/manual/en/class.serializable.php
* @throws InvalidUuidStringException
*/
+ #[ReturnTypeWillChange]
public function unserialize($serialized)
{
$uuid = self::fromString($serialized);
@@ -244,6 +256,23 @@ class Uuid implements UuidInterface
$this->fields = $uuid->fields;
}
+ /**
+ * @param array{string: string} $serialized
+ * @return void
+ * @throws InvalidUuidStringException
+ */
+ #[ReturnTypeWillChange]
+ public function __unserialize(array $serialized)
+ {
+ // @codeCoverageIgnoreStart
+ if (!isset($serialized['string'])) {
+ throw new InvalidUuidStringException();
+ }
+ // @codeCoverageIgnoreEnd
+
+ $this->unserialize($serialized['string']);
+ }
+
public function compareTo(UuidInterface $other)
{
if ($this->getMostSignificantBitsHex() < $other->getMostSignificantBitsHex()) {
From e6e2d78979b0819b85e1307ac80c2a1d7fbbaf84 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 23 Sep 2021 17:03:00 -0500
Subject: [PATCH 17/74] Disallow PHPUnit 9.0-9.2 and show deprecations
---
composer.json | 2 +-
tests/bootstrap.php | 2 --
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/composer.json b/composer.json
index cb69fca..e6f440a 100644
--- a/composer.json
+++ b/composer.json
@@ -36,7 +36,7 @@
"paragonie/random-lib": "^2",
"php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
"php-parallel-lint/php-parallel-lint": "^1.3",
- "phpunit/phpunit": ">=4.8.36",
+ "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
"squizlabs/php_codesniffer": "^3.5",
"yoast/phpunit-polyfills": "^1.0"
},
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 052ea4f..e281141 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -1,8 +1,6 @@
Date: Thu, 23 Sep 2021 19:10:50 -0500
Subject: [PATCH 18/74] Run builds on Windows
---
.github/workflows/continuous-integration.yml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index fc18ae1..8375091 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -62,7 +62,7 @@ jobs:
unit-tests:
name: "Unit Tests"
- runs-on: "ubuntu-latest"
+ runs-on: ${{ matrix.operating-system }}
strategy:
fail-fast: false
@@ -77,6 +77,9 @@ jobs:
- "7.3"
- "7.4"
- "8.0"
+ operating-system:
+ - "ubuntu-latest"
+ - "windows-latest"
include:
- php-version: "5.4"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
@@ -85,6 +88,7 @@ jobs:
- php-version: "5.6"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
- php-version: "8.1"
+ operating-system: "ubuntu-latest"
composer-options: "--ignore-platform-req=php"
steps:
From c4849b9a1abea06d9c71785d82c6c59317fe6cd8 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 23 Sep 2021 19:12:52 -0500
Subject: [PATCH 19/74] Fix Windows builds
---
.github/workflows/continuous-integration.yml | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 8375091..e5161db 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -92,10 +92,17 @@ jobs:
composer-options: "--ignore-platform-req=php"
steps:
+ - name: "Configure Git (for Windows)"
+ if: ${{ matrix.operating-system == 'windows-latest' }}
+ run: |
+ git config --system core.autocrlf false
+ git config --system core.eol lf
+
- name: "Checkout repository"
uses: "actions/checkout@v2"
- name: "Install dependencies (apt)"
+ if: ${{ matrix.operating-system == 'ubuntu-latest' }}
run: |
sudo apt-get update
sudo apt-get -y install bsdmainutils libsodium-dev uuid-dev
From 5c08654f98877eb588bb05e97eb306103675c6a3 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 24 Sep 2021 11:55:30 -0500
Subject: [PATCH 20/74] Move exception expectation
---
tests/UuidTest.php | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tests/UuidTest.php b/tests/UuidTest.php
index 65594d4..a581da0 100644
--- a/tests/UuidTest.php
+++ b/tests/UuidTest.php
@@ -1878,10 +1878,9 @@ class UuidTest extends TestCase
{
Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true)));
- $uuid = Uuid::uuid1();
-
$this->expectException('Ramsey\Uuid\Exception\UnsatisfiedDependencyException');
+ $uuid = Uuid::uuid1();
$uuid->getInteger();
}
From fd7961ce818cfa560b24ff39f36e1ddff01f4681 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 24 Sep 2021 12:18:24 -0500
Subject: [PATCH 21/74] Only attempting loading extensions on Ubuntu
---
.github/workflows/continuous-integration.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index e5161db..da4c83a 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -82,10 +82,13 @@ jobs:
- "windows-latest"
include:
- php-version: "5.4"
+ operating-system: "ubuntu-latest"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
- php-version: "5.5"
+ operating-system: "ubuntu-latest"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
- php-version: "5.6"
+ operating-system: "ubuntu-latest"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
- php-version: "8.1"
operating-system: "ubuntu-latest"
From 893211ef8432795338c90a81bf0f34e2352f7a6b Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 24 Sep 2021 12:33:33 -0500
Subject: [PATCH 22/74] Fiddle with the build matrix to fix Windows issues
---
.github/workflows/continuous-integration.yml | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index da4c83a..0a238d7 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -90,8 +90,21 @@ jobs:
- php-version: "5.6"
operating-system: "ubuntu-latest"
extensions: ", libsodium-1.0.7, uuid-1.0.4"
+ - php-version: "7.0"
+ extensions: ", sodium, uuid"
+ - php-version: "7.1"
+ extensions: ", sodium, uuid"
+ - php-version: "7.2"
+ extensions: ", sodium, uuid"
+ - php-version: "7.3"
+ extensions: ", sodium, uuid"
+ - php-version: "7.4"
+ extensions: ", sodium, uuid"
+ - php-version: "8.0"
+ extensions: ", sodium, uuid"
- php-version: "8.1"
operating-system: "ubuntu-latest"
+ extensions: ", sodium, uuid"
composer-options: "--ignore-platform-req=php"
steps:
@@ -115,7 +128,7 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
- extensions: "bcmath, ctype, gmp, sodium, uuid ${{ matrix.extensions }}"
+ extensions: "bcmath, ctype, gmp ${{ matrix.extensions }}"
coverage: "none"
ini-values: "memory_limit=-1"
From 1b074f4a1c1c78f4c92b45b2db752a73185d2585 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 24 Sep 2021 12:38:13 -0500
Subject: [PATCH 23/74] Lock 3.x to PHP 8.1.x and lower
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index e6f440a..7034822 100644
--- a/composer.json
+++ b/composer.json
@@ -21,7 +21,7 @@
}
],
"require": {
- "php": "^5.4 | ^7 | ^8",
+ "php": "^5.4 | ^7 | ~8.0.0 | ~8.1.0",
"ext-json": "*",
"paragonie/random_compat": "^1 | ^2 | ^9.99.99",
"symfony/polyfill-ctype": "^1.8"
From 43439cdb79b6fc938c8d59c9c27a985c30c3fa99 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 24 Sep 2021 13:07:14 -0500
Subject: [PATCH 24/74] Update badges for 3.x
---
README.md | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 28fa5c9..3f0d2f4 100644
--- a/README.md
+++ b/README.md
@@ -6,9 +6,10 @@
changed to `ramsey/uuid` and `Ramsey\Uuid`, respectively.*
[![Source Code][badge-source]][source]
-[![Latest Version][badge-release]][release]
-[![Software License][badge-license]][license]
+[![Series][badge-series]][series]
+[![Upgrade][badge-upgrade]][upgrade]
[![PHP Version][badge-php]][php]
+[![Software License][badge-license]][license]
[![Build Status][badge-build]][build]
[![Coverage Status][badge-coverage]][coverage]
@@ -170,14 +171,16 @@ information.
[contributing.md]: https://github.com/ramsey/uuid/blob/master/.github/CONTRIBUTING.md
[badge-source]: https://img.shields.io/badge/source-ramsey/uuid-blue.svg?style=flat-square
-[badge-release]: https://img.shields.io/packagist/v/ramsey/uuid.svg?style=flat-square&label=release
-[badge-license]: https://img.shields.io/packagist/l/ramsey/uuid.svg?style=flat-square
-[badge-php]: https://img.shields.io/packagist/php-v/ramsey/uuid/3.x-dev.svg?style=flat-square
+[badge-series]: https://img.shields.io/badge/series-3.x-darkcyan.svg?style=flat-square
+[badge-upgrade]: https://img.shields.io/packagist/v/ramsey/uuid.svg?style=flat-square&label=upgrade&colorB=darkred
+[badge-license]: https://img.shields.io/packagist/l/ramsey/uuid.svg?style=flat-square&colorB=darkcyan
+[badge-php]: https://img.shields.io/packagist/php-v/ramsey/uuid/3.x-dev.svg?style=flat-square&colorB=%238892BF
[badge-build]: https://img.shields.io/github/workflow/status/ramsey/uuid/build/3.x.svg?logo=github&style=flat-square
[badge-coverage]: https://img.shields.io/codecov/c/gh/ramsey/uuid/3.x.svg?style=flat-square&logo=codecov
[source]: https://github.com/ramsey/uuid
-[release]: https://packagist.org/packages/ramsey/uuid
+[series]: https://packagist.org/packages/ramsey/uuid/tree/3.x
+[upgrade]: https://packagist.org/packages/ramsey/uuid
[license]: https://github.com/ramsey/uuid/blob/master/LICENSE
[php]: https://php.net
[build]: https://github.com/ramsey/uuid/actions/workflows/continuous-integration.yml?query=branch%3A3.x
From ada8d27a5cfc2d41d2a5a4108b8a7070a5ebb3e4 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 24 Sep 2021 13:08:40 -0500
Subject: [PATCH 25/74] Fix links in README
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 3f0d2f4..544df1a 100644
--- a/README.md
+++ b/README.md
@@ -178,8 +178,8 @@ information.
[badge-build]: https://img.shields.io/github/workflow/status/ramsey/uuid/build/3.x.svg?logo=github&style=flat-square
[badge-coverage]: https://img.shields.io/codecov/c/gh/ramsey/uuid/3.x.svg?style=flat-square&logo=codecov
-[source]: https://github.com/ramsey/uuid
-[series]: https://packagist.org/packages/ramsey/uuid/tree/3.x
+[source]: https://github.com/ramsey/uuid/tree/3.x
+[series]: https://packagist.org/packages/ramsey/uuid
[upgrade]: https://packagist.org/packages/ramsey/uuid
[license]: https://github.com/ramsey/uuid/blob/master/LICENSE
[php]: https://php.net
From 7577465251660d69c719b0ac461d827105f3e6a4 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 24 Sep 2021 13:11:15 -0500
Subject: [PATCH 26/74] Ignore the changelog in exported packages
---
.gitattributes | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitattributes b/.gitattributes
index ae09278..44187e0 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,6 +1,7 @@
.gitattributes export-ignore
.github/ export-ignore
.gitignore export-ignore
+CHANGELOG.md export-ignore
codecov.yml export-ignore
docs/ export-ignore
phpstan.neon export-ignore
From d6b829b1a3e076c11a55bc6e00619532c25978bd Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 24 Sep 2021 13:21:52 -0500
Subject: [PATCH 27/74] Remove changelog version links
---
CHANGELOG.md | 158 +++++++++++++++++----------------------------------
1 file changed, 52 insertions(+), 106 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8276415..0d50771 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,14 +21,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Security
-## [3.9.4] - 2021-08-06
+## 3.9.4 - 2021-08-06
### Fixed
* Allow installation of paragonie/random_compat v9.99.100 (for PHP 8 compatibility).
-## [3.9.3] - 2020-02-20
+## 3.9.3 - 2020-02-20
### Fixed
@@ -45,7 +45,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
the time is `1970-01-01 00:00:01`. No rounding should occur.
-## [3.9.2] - 2019-12-17
+## 3.9.2 - 2019-12-17
### Fixed
@@ -54,7 +54,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
emitted on hosts that do not grant permission to read these files.
-## [3.9.1] - 2019-12-01
+## 3.9.1 - 2019-12-01
### Fixed
@@ -64,7 +64,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
resolved.
-## [3.9.0] - 2019-11-30
+## 3.9.0 - 2019-11-30
### Added
@@ -96,7 +96,7 @@ These will be removed in ramsey/uuid version 4.0.0:
cases when `php_uname()` is disabled for security reasons.
-## [3.8.0] - 2018-07-19
+## 3.8.0 - 2018-07-19
### Added
@@ -107,7 +107,7 @@ These will be removed in ramsey/uuid version 4.0.0:
* Annotate thrown exceptions for improved IDE hinting
-## [3.7.3] - 2018-01-19
+## 3.7.3 - 2018-01-19
### Fixed
@@ -120,7 +120,7 @@ These will be removed in ramsey/uuid version 4.0.0:
* Switch to `random_int()` from `mt_rand()` for better random numbers
-## [3.7.2] - 2018-01-13
+## 3.7.2 - 2018-01-13
### Fixed
@@ -128,7 +128,7 @@ These will be removed in ramsey/uuid version 4.0.0:
reliable way to identify the node on Docker images, etc.
-## [3.7.1] - 2017-09-22
+## 3.7.1 - 2017-09-22
### Fixed
@@ -139,7 +139,7 @@ These will be removed in ramsey/uuid version 4.0.0:
* Use `random_bytes()` when generating random nodes
-## [3.7.0] - 2017-08-04
+## 3.7.0 - 2017-08-04
### Added
@@ -151,14 +151,14 @@ These will be removed in ramsey/uuid version 4.0.0:
* `Uuid::UUID_TYPE_HASH_SHA1`
-## [3.6.1] - 2017-03-26
+## 3.6.1 - 2017-03-26
### Fixed
* Optimize UUID string decoding by using `str_pad()` instead of `sprintf()`
-## [3.6.0] - 2017-03-18
+## 3.6.0 - 2017-03-18
### Added
@@ -172,14 +172,14 @@ These will be removed in ramsey/uuid version 4.0.0:
and `dechex()` instead of `sprintf()`)
-## [3.5.2] - 2016-11-22
+## 3.5.2 - 2016-11-22
### Fixed
* Improve test coverage
-## [3.5.1] - 2016-10-02
+## 3.5.1 - 2016-10-02
### Fixed
@@ -187,7 +187,7 @@ These will be removed in ramsey/uuid version 4.0.0:
mixed cases
-## [3.5.0] - 2016-08-02
+## 3.5.0 - 2016-08-02
### Added
@@ -200,14 +200,14 @@ These will be removed in ramsey/uuid version 4.0.0:
system node
-## [3.4.1] - 2016-04-23
+## 3.4.1 - 2016-04-23
### Fixed
* Fix test that violated a PHP CodeSniffer rule, breaking the build
-## [3.4.0] - 2016-04-23
+## 3.4.0 - 2016-04-23
### Added
@@ -217,7 +217,7 @@ These will be removed in ramsey/uuid version 4.0.0:
* Improve logic of `CombGenerator` for COMB sequential UUIDs
-## [3.3.0] - 2016-03-22
+## 3.3.0 - 2016-03-22
### Security
@@ -226,7 +226,7 @@ These will be removed in ramsey/uuid version 4.0.0:
this addresses and fixes the [collision issue]
-## [3.2.0] - 2016-02-17
+## 3.2.0 - 2016-02-17
### Added
@@ -234,7 +234,7 @@ These will be removed in ramsey/uuid version 4.0.0:
a random bytes generator when creating UUIDs
-## [3.1.0] - 2015-12-17
+## 3.1.0 - 2015-12-17
### Added
@@ -242,14 +242,14 @@ These will be removed in ramsey/uuid version 4.0.0:
serialize/unserialize UUID objects
-## [3.0.1] - 2015-10-21
+## 3.0.1 - 2015-10-21
### Added
* Adopt the [Contributor Code of Conduct] for this project
-## [3.0.0] - 2015-09-28
+## 3.0.0 - 2015-09-28
The 3.0.0 release represents a significant step for the ramsey/uuid library.
While the simple and familiar API used in previous versions remains intact, this
@@ -316,7 +316,7 @@ versions leading up to this release.*
* Fix exception message for `DegradedNumberConverter::fromHex()`
-## [3.0.0-beta1] - 2015-08-31
+## 3.0.0-beta1 - 2015-08-31
### Fixed
@@ -328,7 +328,7 @@ versions leading up to this release.*
* Fix exception message for `DegradedNumberConverter::fromHex()`
-## [3.0.0-alpha3] - 2015-07-28
+## 3.0.0-alpha3 - 2015-07-28
### Added
@@ -344,7 +344,7 @@ versions leading up to this release.*
default `TimeGenerator`
-## [3.0.0-alpha2] - 2015-07-28
+## 3.0.0-alpha2 - 2015-07-28
### Added
@@ -366,7 +366,7 @@ versions leading up to this release.*
* Remove `PeclUuidFactory` in favor of using pecl-uuid with generators
-## [3.0.0-alpha1] - 2015-07-16
+## 3.0.0-alpha1 - 2015-07-16
### Added
@@ -400,7 +400,7 @@ versions leading up to this release.*
* Remove `Uuid::VERSION` package version constant
-## [2.9.0] - 2016-03-22
+## 2.9.0 - 2016-03-22
### Security
@@ -409,28 +409,28 @@ versions leading up to this release.*
this addresses and fixes the [collision issue]
-## [2.8.4] - 2015-12-17
+## 2.8.4 - 2015-12-17
### Added
* Add support for symfony/console v3 in the `uuid` CLI application
-## [2.8.3] - 2015-08-31
+## 2.8.3 - 2015-08-31
### Fixed
* Fix exception message in `Uuid::calculateUuidTime()`
-## [2.8.2] - 2015-07-23
+## 2.8.2 - 2015-07-23
### Fixed
* Ensure the release tag makes it into the rhumsaa/uuid package
-## [2.8.1] - 2015-06-16
+## 2.8.1 - 2015-06-16
### Fixed
@@ -439,7 +439,7 @@ versions leading up to this release.*
runtime
-## [2.8.0] - 2014-11-09
+## 2.8.0 - 2014-11-09
### Added
@@ -448,32 +448,31 @@ versions leading up to this release.*
### Fixed
-* Improve Doctrine conversion to Uuid or string for the ramsey/uuid [Doctrine
- field type]
+* Improve Doctrine conversion to Uuid or string for the ramsey/uuid [Doctrine field type]
-## [2.7.4] - 2014-10-29
+## 2.7.4 - 2014-10-29
### Fixed
* Change loop in `generateBytes()` from `foreach` to `for`
-## [2.7.3] - 2014-08-27
+## 2.7.3 - 2014-08-27
### Fixed
* Fix upper range for `mt_rand` used in version 4 UUIDs
-## [2.7.2] - 2014-07-28
+## 2.7.2 - 2014-07-28
### Changed
* Upgrade to PSR-4 autoloading
-## [2.7.1] - 2014-02-19
+## 2.7.1 - 2014-02-19
### Fixed
@@ -481,14 +480,14 @@ versions leading up to this release.*
* Support symfony/console 2.3 (LTS version)
-## [2.7.0] - 2014-01-31
+## 2.7.0 - 2014-01-31
### Added
* Add `Uuid::VALID_PATTERN` constant containing a UUID validation regex pattern
-## [2.6.1] - 2014-01-27
+## 2.6.1 - 2014-01-27
### Fixed
@@ -496,7 +495,7 @@ versions leading up to this release.*
autoloader when installed in another project
-## [2.6.0] - 2014-01-17
+## 2.6.0 - 2014-01-17
### Added
@@ -509,14 +508,14 @@ versions leading up to this release.*
* Require moontoast/math as part of the regular package requirements
-## [2.5.0] - 2013-10-30
+## 2.5.0 - 2013-10-30
### Added
* Use `openssl_random_pseudo_bytes()`, if available, to generate random bytes
-## [2.4.0] - 2013-07-29
+## 2.4.0 - 2013-07-29
### Added
@@ -524,21 +523,21 @@ versions leading up to this release.*
* Support string UUIDs without dashes passed to `Uuid::fromString()`
-## [2.3.0] - 2013-07-16
+## 2.3.0 - 2013-07-16
### Added
* Support creation of UUIDs from bytes with `Uuid::fromBytes()`
-## [2.2.0] - 2013-07-04
+## 2.2.0 - 2013-07-04
### Added
* Add `Doctrine\UuidType::requiresSQLCommentHint()` method
-## [2.1.2] - 2013-07-03
+## 2.1.2 - 2013-07-03
### Fixed
@@ -546,21 +545,21 @@ versions leading up to this release.*
digits; this ensures that case in the node is converted to lowercase
-## [2.1.1] - 2013-04-29
+## 2.1.1 - 2013-04-29
### Fixed
* Fix bug in `Uuid::isValid()` where the NIL UUID was not reported as valid
-## [2.1.0] - 2013-04-15
+## 2.1.0 - 2013-04-15
### Added
* Allow checking the validity of a UUID through the `Uuid::isValid()` method
-## [2.0.0] - 2013-02-11
+## 2.0.0 - 2013-02-11
### Added
@@ -576,21 +575,21 @@ versions leading up to this release.*
* Move `UnsupportedOperationException` to the `Exception` subnamespace
-## [1.1.2] - 2012-11-29
+## 1.1.2 - 2012-11-29
### Fixed
* Relax [Doctrine field type] conversion rules for UUIDs
-## [1.1.1] - 2012-08-27
+## 1.1.1 - 2012-08-27
### Fixed
* Remove `final` keyword from `Uuid` class
-## [1.1.0] - 2012-08-06
+## 1.1.0 - 2012-08-06
### Added
@@ -598,7 +597,7 @@ versions leading up to this release.*
field mapping type
-## [1.0.0] - 2012-07-19
+## 1.0.0 - 2012-07-19
### Added
@@ -614,56 +613,3 @@ versions leading up to this release.*
[doctrine field type]: http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html
[ramsey/uuid-doctrine]: https://github.com/ramsey/uuid-doctrine
[ramsey/uuid-console]: https://github.com/ramsey/uuid-console
-
-[unreleased]: https://github.com/ramsey/uuid/compare/3.9.4...3.x
-[3.9.4]: https://github.com/ramsey/uuid/compare/3.9.2...3.9.4
-[3.9.3]: https://github.com/ramsey/uuid/compare/3.9.2...3.9.3
-[3.9.2]: https://github.com/ramsey/uuid/compare/3.9.1...3.9.2
-[3.9.1]: https://github.com/ramsey/uuid/compare/3.9.0...3.9.1
-[3.9.0]: https://github.com/ramsey/uuid/compare/3.8.0...3.9.0
-[3.8.0]: https://github.com/ramsey/uuid/compare/3.7.3...3.8.0
-[3.7.3]: https://github.com/ramsey/uuid/compare/3.7.2...3.7.3
-[3.7.2]: https://github.com/ramsey/uuid/compare/3.7.1...3.7.2
-[3.7.1]: https://github.com/ramsey/uuid/compare/3.7.0...3.7.1
-[3.7.0]: https://github.com/ramsey/uuid/compare/3.6.1...3.7.0
-[3.6.1]: https://github.com/ramsey/uuid/compare/3.6.0...3.6.1
-[3.6.0]: https://github.com/ramsey/uuid/compare/3.5.2...3.6.0
-[3.5.2]: https://github.com/ramsey/uuid/compare/3.5.1...3.5.2
-[3.5.1]: https://github.com/ramsey/uuid/compare/3.5.0...3.5.1
-[3.5.0]: https://github.com/ramsey/uuid/compare/3.4.1...3.5.0
-[3.4.1]: https://github.com/ramsey/uuid/compare/3.4.0...3.4.1
-[3.4.0]: https://github.com/ramsey/uuid/compare/3.3.0...3.4.0
-[3.3.0]: https://github.com/ramsey/uuid/compare/3.2.0...3.3.0
-[3.2.0]: https://github.com/ramsey/uuid/compare/3.1.0...3.2.0
-[3.1.0]: https://github.com/ramsey/uuid/compare/3.0.1...3.1.0
-[3.0.1]: https://github.com/ramsey/uuid/compare/3.0.0...3.0.1
-[3.0.0]: https://github.com/ramsey/uuid/compare/3.0.0-beta1...3.0.0
-[3.0.0-beta1]: https://github.com/ramsey/uuid/compare/3.0.0-alpha3...3.0.0-beta1
-[3.0.0-alpha3]: https://github.com/ramsey/uuid/compare/3.0.0-alpha2...3.0.0-alpha3
-[3.0.0-alpha2]: https://github.com/ramsey/uuid/compare/3.0.0-alpha1...3.0.0-alpha2
-[3.0.0-alpha1]: https://github.com/ramsey/uuid/compare/2.9.0...3.0.0-alpha1
-[2.9.0]: https://github.com/ramsey/uuid/compare/2.8.4...2.9.0
-[2.8.4]: https://github.com/ramsey/uuid/compare/2.8.3...2.8.4
-[2.8.3]: https://github.com/ramsey/uuid/compare/2.8.2...2.8.3
-[2.8.2]: https://github.com/ramsey/uuid/compare/2.8.1...2.8.2
-[2.8.1]: https://github.com/ramsey/uuid/compare/2.8.0...2.8.1
-[2.8.0]: https://github.com/ramsey/uuid/compare/2.7.4...2.8.0
-[2.7.4]: https://github.com/ramsey/uuid/compare/2.7.3...2.7.4
-[2.7.3]: https://github.com/ramsey/uuid/compare/2.7.2...2.7.3
-[2.7.2]: https://github.com/ramsey/uuid/compare/2.7.1...2.7.2
-[2.7.1]: https://github.com/ramsey/uuid/compare/2.7.0...2.7.1
-[2.7.0]: https://github.com/ramsey/uuid/compare/2.6.1...2.7.0
-[2.6.1]: https://github.com/ramsey/uuid/compare/2.6.0...2.6.1
-[2.6.0]: https://github.com/ramsey/uuid/compare/2.5.0...2.6.0
-[2.5.0]: https://github.com/ramsey/uuid/compare/2.4.0...2.5.0
-[2.4.0]: https://github.com/ramsey/uuid/compare/2.3.0...2.4.0
-[2.3.0]: https://github.com/ramsey/uuid/compare/2.2.0...2.3.0
-[2.2.0]: https://github.com/ramsey/uuid/compare/2.1.2...2.2.0
-[2.1.2]: https://github.com/ramsey/uuid/compare/2.1.1...2.1.2
-[2.1.1]: https://github.com/ramsey/uuid/compare/2.1.0...2.1.1
-[2.1.0]: https://github.com/ramsey/uuid/compare/2.0.0...2.1.0
-[2.0.0]: https://github.com/ramsey/uuid/compare/1.1.2...2.0.0
-[1.1.2]: https://github.com/ramsey/uuid/compare/1.1.1...1.1.2
-[1.1.1]: https://github.com/ramsey/uuid/compare/1.1.0...1.1.1
-[1.1.0]: https://github.com/ramsey/uuid/compare/1.0.0...1.1.0
-[1.0.0]: https://github.com/ramsey/uuid/commits/1.0.0
From e62af90c1cf1552167e69e68c4c96b6a07a919c7 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 24 Sep 2021 13:22:07 -0500
Subject: [PATCH 28/74] Prepare changelog for release 3.9.5
---
CHANGELOG.md | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d50771..353bb7e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,21 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
-
-## [Unreleased]
-
-### Added
-
-### Changed
-
-### Deprecated
-
-### Removed
+## 3.9.5 - 2021-09-24
### Fixed
-### Security
-
+* Indicate support for PHP 8.1, using `~8.1.0` to prevent installations on 8.2
+ until the library is ready.
## 3.9.4 - 2021-08-06
From ffa80ab953edd85d5b6c004f96181a538aad35a3 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Sat, 25 Sep 2021 18:07:42 -0500
Subject: [PATCH 29/74] Switch back to ^8.0 in the PHP version requirement for
3.9.x
---
CHANGELOG.md | 9 +++++++++
composer.json | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 353bb7e..002de3b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## 3.9.6 - 2021-09-25
+
+### Fixed
+
+* Switch back to `^8.0` in the PHP version requirement.
+
+
## 3.9.5 - 2021-09-24
### Fixed
@@ -12,6 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Indicate support for PHP 8.1, using `~8.1.0` to prevent installations on 8.2
until the library is ready.
+
## 3.9.4 - 2021-08-06
### Fixed
diff --git a/composer.json b/composer.json
index 7034822..a618595 100644
--- a/composer.json
+++ b/composer.json
@@ -21,7 +21,7 @@
}
],
"require": {
- "php": "^5.4 | ^7 | ~8.0.0 | ~8.1.0",
+ "php": "^5.4 | ^7.0 | ^8.0",
"ext-json": "*",
"paragonie/random_compat": "^1 | ^2 | ^9.99.99",
"symfony/polyfill-ctype": "^1.8"
From 7201bafdb2c5bff4136ab1e7b32fb02392cedca3 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Sun, 27 Mar 2022 12:27:45 -0500
Subject: [PATCH 30/74] chore: remove branch-alias and allow plugins
---
composer.json | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/composer.json b/composer.json
index a618595..8f5505d 100644
--- a/composer.json
+++ b/composer.json
@@ -51,11 +51,12 @@
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter"
},
"config": {
- "sort-packages": true
- },
- "extra": {
- "branch-alias": {
- "dev-master": "3.x-dev"
+ "sort-packages": true,
+ "allow-plugins": {
+ "phpstan/extension-installer": true,
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "ergebnis/composer-normalize": true,
+ "captainhook/plugin-composer": true
}
},
"replace": {
From 4d817640fa104a2195b5167c19f251c313fcd1db Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 12 Sep 2022 17:14:33 -0500
Subject: [PATCH 31/74] Bump phpstan/phpstan from 1.8.4 to 1.8.5
---
composer.lock | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/composer.lock b/composer.lock
index 444ac0a..d78caa5 100644
--- a/composer.lock
+++ b/composer.lock
@@ -3044,16 +3044,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.8.4",
+ "version": "1.8.5",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "eed4c9da531f6ebb4787235b6fb486e2c20f34e5"
+ "reference": "f6598a5ff12ca4499a836815e08b4d77a2ddeb20"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/eed4c9da531f6ebb4787235b6fb486e2c20f34e5",
- "reference": "eed4c9da531f6ebb4787235b6fb486e2c20f34e5",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f6598a5ff12ca4499a836815e08b4d77a2ddeb20",
+ "reference": "f6598a5ff12ca4499a836815e08b4d77a2ddeb20",
"shasum": ""
},
"require": {
@@ -3083,7 +3083,7 @@
],
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
- "source": "https://github.com/phpstan/phpstan/tree/1.8.4"
+ "source": "https://github.com/phpstan/phpstan/tree/1.8.5"
},
"funding": [
{
@@ -3099,7 +3099,7 @@
"type": "tidelift"
}
],
- "time": "2022-09-03T13:08:04+00:00"
+ "time": "2022-09-07T16:05:32+00:00"
},
{
"name": "phpstan/phpstan-mockery",
From 89905d19485b9235e44a5841035205df77145529 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 12 Sep 2022 18:00:21 -0500
Subject: [PATCH 32/74] chore: remove deprecation notices
---
src/DeprecatedUuidFactoryInterface.php | 180 -------------------------
src/DeprecatedUuidInterface.php | 5 +-
src/FeatureSet.php | 2 -
src/Uuid.php | 39 ------
src/UuidFactory.php | 4 -
src/UuidFactoryInterface.php | 126 ++++++++++++++++-
6 files changed, 126 insertions(+), 230 deletions(-)
delete mode 100644 src/DeprecatedUuidFactoryInterface.php
diff --git a/src/DeprecatedUuidFactoryInterface.php b/src/DeprecatedUuidFactoryInterface.php
deleted file mode 100644
index 2ea38f8..0000000
--- a/src/DeprecatedUuidFactoryInterface.php
+++ /dev/null
@@ -1,180 +0,0 @@
-
- * @license http://opensource.org/licenses/MIT MIT
- */
-
-declare(strict_types=1);
-
-namespace Ramsey\Uuid;
-
-use DateTimeInterface;
-use Ramsey\Uuid\Type\Hexadecimal;
-use Ramsey\Uuid\Type\Integer as IntegerObject;
-use Ramsey\Uuid\Validator\ValidatorInterface;
-
-/**
- * This interface encapsulates deprecated methods for ramsey/uuid; this
- * interface and its methods will be removed in ramsey/uuid 5.0.0.
- *
- * @deprecated This interface and its methods will be removed in ramsey/uuid 5.0.0.
- */
-interface DeprecatedUuidFactoryInterface
-{
- /**
- * Creates a UUID from a DateTimeInterface instance
- *
- * @deprecated In ramsey/uuid version 5, UUID factories will no longer have
- * dedicated methods for creating datetime-based UUIDs. Use a dedicated
- * factory to generate UUIDs from a DateTime instance.
- *
- * @param DateTimeInterface $dateTime The date and time
- * @param Hexadecimal|null $node A 48-bit number representing the hardware
- * address
- * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
- * that could arise when the clock is set backwards in time or if the
- * node ID changes
- *
- * @return UuidInterface A UuidInterface instance that represents a
- * version 1 UUID created from a DateTimeInterface instance
- */
- public function fromDateTime(
- DateTimeInterface $dateTime,
- ?Hexadecimal $node = null,
- ?int $clockSeq = null
- ): UuidInterface;
-
- /**
- * Returns the validator to use for the factory
- *
- * @deprecated In ramsey/uuid version 5, UUID factories will no longer have
- * dedicated methods for getting validators. Use a dedicated validator
- * class to validate UUIDs.
- *
- * @psalm-mutation-free
- */
- public function getValidator(): ValidatorInterface;
-
- /**
- * Returns a version 1 (time-based) UUID from a host ID, sequence number,
- * and the current time
- *
- * @deprecated In ramsey/uuid version 5, UUID factories will no longer have
- * methods specific to creating subtypes. Instead, version 5 will use
- * dedicated factories for each subtype.
- *
- * @param Hexadecimal|int|string|null $node A 48-bit number representing the
- * hardware address; this number may be represented as an integer or a
- * hexadecimal string
- * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
- * that could arise when the clock is set backwards in time or if the
- * node ID changes
- *
- * @return UuidInterface A UuidInterface instance that represents a
- * version 1 UUID
- */
- public function uuid1($node = null, ?int $clockSeq = null): UuidInterface;
-
- /**
- * Returns a version 2 (DCE Security) UUID from a local domain, local
- * identifier, host ID, clock sequence, and the current time
- *
- * @deprecated In ramsey/uuid version 5, UUID factories will no longer have
- * methods specific to creating subtypes. Instead, version 5 will use
- * dedicated factories for each subtype.
- *
- * @param int $localDomain The local domain to use when generating bytes,
- * according to DCE Security
- * @param IntegerObject|null $localIdentifier The local identifier for the
- * given domain; this may be a UID or GID on POSIX systems, if the local
- * domain is person or group, or it may be a site-defined identifier
- * if the local domain is org
- * @param Hexadecimal|null $node A 48-bit number representing the hardware
- * address
- * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
- * that could arise when the clock is set backwards in time or if the
- * node ID changes
- *
- * @return UuidInterface A UuidInterface instance that represents a
- * version 2 UUID
- */
- public function uuid2(
- int $localDomain,
- ?IntegerObject $localIdentifier = null,
- ?Hexadecimal $node = null,
- ?int $clockSeq = null
- ): UuidInterface;
-
- /**
- * Returns a version 3 (name-based) UUID based on the MD5 hash of a
- * namespace ID and a name
- *
- * @deprecated In ramsey/uuid version 5, UUID factories will no longer have
- * methods specific to creating subtypes. Instead, version 5 will use
- * dedicated factories for each subtype.
- *
- * @param string|UuidInterface $ns The namespace (must be a valid UUID)
- * @param string $name The name to use for creating a UUID
- *
- * @return UuidInterface A UuidInterface instance that represents a
- * version 3 UUID
- *
- * @psalm-pure
- */
- public function uuid3($ns, string $name): UuidInterface;
-
- /**
- * Returns a version 4 (random) UUID
- *
- * @deprecated In ramsey/uuid version 5, UUID factories will no longer have
- * methods specific to creating subtypes. Instead, version 5 will use
- * dedicated factories for each subtype.
- *
- * @return UuidInterface A UuidInterface instance that represents a
- * version 4 UUID
- */
- public function uuid4(): UuidInterface;
-
- /**
- * Returns a version 5 (name-based) UUID based on the SHA-1 hash of a
- * namespace ID and a name
- *
- * @deprecated In ramsey/uuid version 5, UUID factories will no longer have
- * methods specific to creating subtypes. Instead, version 5 will use
- * dedicated factories for each subtype.
- *
- * @param string|UuidInterface $ns The namespace (must be a valid UUID)
- * @param string $name The name to use for creating a UUID
- *
- * @return UuidInterface A UuidInterface instance that represents a
- * version 5 UUID
- *
- * @psalm-pure
- */
- public function uuid5($ns, string $name): UuidInterface;
-
- /**
- * Returns a version 6 (ordered-time) UUID from a host ID, sequence number,
- * and the current time
- *
- * @deprecated In ramsey/uuid version 5, UUID factories will no longer have
- * methods specific to creating subtypes. Instead, version 5 will use
- * dedicated factories for each subtype.
- *
- * @param Hexadecimal|null $node A 48-bit number representing the hardware
- * address
- * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
- * that could arise when the clock is set backwards in time or if the
- * node ID changes
- *
- * @return UuidInterface A UuidInterface instance that represents a
- * version 6 UUID
- */
- public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface;
-}
diff --git a/src/DeprecatedUuidInterface.php b/src/DeprecatedUuidInterface.php
index 017d16d..ac01a79 100644
--- a/src/DeprecatedUuidInterface.php
+++ b/src/DeprecatedUuidInterface.php
@@ -18,10 +18,7 @@ use DateTimeInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
/**
- * This interface encapsulates deprecated methods for ramsey/uuid; this
- * interface and its methods will be removed in ramsey/uuid 5.0.0.
- *
- * @deprecated This interface and its methods will be removed in ramsey/uuid 5.0.0.
+ * This interface encapsulates deprecated methods for ramsey/uuid
*
* @psalm-immutable
*/
diff --git a/src/FeatureSet.php b/src/FeatureSet.php
index 0a71436..819f99a 100644
--- a/src/FeatureSet.php
+++ b/src/FeatureSet.php
@@ -58,8 +58,6 @@ use const PHP_INT_SIZE;
*
* A feature set is used by UuidFactory to determine the available features and
* capabilities of the environment.
- *
- * @deprecated This class will go away in ramsey/uuid version 5.
*/
class FeatureSet
{
diff --git a/src/Uuid.php b/src/Uuid.php
index 7d0317f..019cec8 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -85,9 +85,6 @@ class Uuid implements UuidInterface
/**
* Variant: reserved, NCS backward compatibility
*
- * @deprecated The Ramsey\Uuid\Variant enum will replace this constant in
- * ramsey/uuid version 5.
- *
* @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
*/
public const RESERVED_NCS = 0;
@@ -95,9 +92,6 @@ class Uuid implements UuidInterface
/**
* Variant: the UUID layout specified in RFC 4122
*
- * @deprecated The Ramsey\Uuid\Variant enum will replace this constant in
- * ramsey/uuid version 5.
- *
* @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
*/
public const RFC_4122 = 2;
@@ -105,9 +99,6 @@ class Uuid implements UuidInterface
/**
* Variant: reserved, Microsoft Corporation backward compatibility
*
- * @deprecated The Ramsey\Uuid\Variant enum will replace this constant in
- * ramsey/uuid version 5.
- *
* @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
*/
public const RESERVED_MICROSOFT = 6;
@@ -115,9 +106,6 @@ class Uuid implements UuidInterface
/**
* Variant: reserved for future definition
*
- * @deprecated The Ramsey\Uuid\Variant enum will replace this constant in
- * ramsey/uuid version 5.
- *
* @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
*/
public const RESERVED_FUTURE = 7;
@@ -130,9 +118,6 @@ class Uuid implements UuidInterface
/**
* Version 1 (time-based) UUID
*
- * @deprecated The Ramsey\Uuid\Version enum will replace this constant in
- * ramsey/uuid version 5.
- *
* @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
*/
public const UUID_TYPE_TIME = 1;
@@ -140,9 +125,6 @@ class Uuid implements UuidInterface
/**
* Version 2 (DCE Security) UUID
*
- * @deprecated The Ramsey\Uuid\Version enum will replace this constant in
- * ramsey/uuid version 5.
- *
* @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
*/
public const UUID_TYPE_DCE_SECURITY = 2;
@@ -155,9 +137,6 @@ class Uuid implements UuidInterface
/**
* Version 3 (name-based and hashed with MD5) UUID
*
- * @deprecated The Ramsey\Uuid\Version enum will replace this constant in
- * ramsey/uuid version 5.
- *
* @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
*/
public const UUID_TYPE_HASH_MD5 = 3;
@@ -165,9 +144,6 @@ class Uuid implements UuidInterface
/**
* Version 4 (random) UUID
*
- * @deprecated The Ramsey\Uuid\Version enum will replace this constant in
- * ramsey/uuid version 5.
- *
* @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
*/
public const UUID_TYPE_RANDOM = 4;
@@ -175,9 +151,6 @@ class Uuid implements UuidInterface
/**
* Version 5 (name-based and hashed with SHA1) UUID
*
- * @deprecated The Ramsey\Uuid\Version enum will replace this constant in
- * ramsey/uuid version 5.
- *
* @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
*/
public const UUID_TYPE_HASH_SHA1 = 5;
@@ -277,10 +250,6 @@ class Uuid implements UuidInterface
* $namespaceSha1Uuid = Uuid::uuid5(Uuid::NAMESPACE_URL, 'http://php.net/');
* ```
*
- * @deprecated ramsey/uuid version 5 will no longer allow direct
- * instantiation of the base Ramsey\Uuid\Uuid class. Instead, you must
- * use factories to create UUID objects.
- *
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
* for converting hex values to/from integers
@@ -433,9 +402,6 @@ class Uuid implements UuidInterface
/**
* Returns the factory used to create UUIDs
- *
- * @deprecated ramsey/uuid version 5 will no longer support getting a
- * factory instance from the base Ramsey\Uuid\Uuid class.
*/
public static function getFactory(): UuidFactoryInterface
{
@@ -449,11 +415,6 @@ class Uuid implements UuidInterface
/**
* Sets the factory used to create UUIDs
*
- * @deprecated ramsey/uuid version 5 will no longer support setting a
- * factory instance on the base Ramsey\Uuid\Uuid class. If you need to
- * customize the properties used to build a UUID, use one of the
- * dedicated factories that version 5 will introduce.
- *
* @param UuidFactoryInterface $factory A factory that will be used by this
* class to create UUIDs
*/
diff --git a/src/UuidFactory.php b/src/UuidFactory.php
index 67ed8ee..6f2cea0 100644
--- a/src/UuidFactory.php
+++ b/src/UuidFactory.php
@@ -43,10 +43,6 @@ use function unpack;
use const STR_PAD_LEFT;
-/**
- * @deprecated UuidFactory will go away in ramsey/uuid version 5. Use dedicated
- * factories for subtypes instead.
- */
class UuidFactory implements UuidFactoryInterface
{
/**
diff --git a/src/UuidFactoryInterface.php b/src/UuidFactoryInterface.php
index e2a1236..bc0e615 100644
--- a/src/UuidFactoryInterface.php
+++ b/src/UuidFactoryInterface.php
@@ -14,11 +14,16 @@ declare(strict_types=1);
namespace Ramsey\Uuid;
+use DateTimeInterface;
+use Ramsey\Uuid\Type\Hexadecimal;
+use Ramsey\Uuid\Type\Integer as IntegerObject;
+use Ramsey\Uuid\Validator\ValidatorInterface;
+
/**
* UuidFactoryInterface defines common functionality all `UuidFactory` instances
* must implement
*/
-interface UuidFactoryInterface extends DeprecatedUuidFactoryInterface
+interface UuidFactoryInterface
{
/**
* Creates a UUID from a byte string
@@ -32,6 +37,25 @@ interface UuidFactoryInterface extends DeprecatedUuidFactoryInterface
*/
public function fromBytes(string $bytes): UuidInterface;
+ /**
+ * Creates a UUID from a DateTimeInterface instance
+ *
+ * @param DateTimeInterface $dateTime The date and time
+ * @param Hexadecimal|null $node A 48-bit number representing the hardware
+ * address
+ * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
+ * that could arise when the clock is set backwards in time or if the
+ * node ID changes
+ *
+ * @return UuidInterface A UuidInterface instance that represents a
+ * version 1 UUID created from a DateTimeInterface instance
+ */
+ public function fromDateTime(
+ DateTimeInterface $dateTime,
+ ?Hexadecimal $node = null,
+ ?int $clockSeq = null
+ ): UuidInterface;
+
/**
* Creates a UUID from a 128-bit integer string
*
@@ -55,4 +79,104 @@ interface UuidFactoryInterface extends DeprecatedUuidFactoryInterface
* @psalm-pure
*/
public function fromString(string $uuid): UuidInterface;
+
+ /**
+ * Returns the validator to use for the factory
+ *
+ * @psalm-mutation-free
+ */
+ public function getValidator(): ValidatorInterface;
+
+ /**
+ * Returns a version 1 (time-based) UUID from a host ID, sequence number,
+ * and the current time
+ *
+ * @param Hexadecimal|int|string|null $node A 48-bit number representing the
+ * hardware address; this number may be represented as an integer or a
+ * hexadecimal string
+ * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
+ * that could arise when the clock is set backwards in time or if the
+ * node ID changes
+ *
+ * @return UuidInterface A UuidInterface instance that represents a
+ * version 1 UUID
+ */
+ public function uuid1($node = null, ?int $clockSeq = null): UuidInterface;
+
+ /**
+ * Returns a version 2 (DCE Security) UUID from a local domain, local
+ * identifier, host ID, clock sequence, and the current time
+ *
+ * @param int $localDomain The local domain to use when generating bytes,
+ * according to DCE Security
+ * @param IntegerObject|null $localIdentifier The local identifier for the
+ * given domain; this may be a UID or GID on POSIX systems, if the local
+ * domain is person or group, or it may be a site-defined identifier
+ * if the local domain is org
+ * @param Hexadecimal|null $node A 48-bit number representing the hardware
+ * address
+ * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
+ * that could arise when the clock is set backwards in time or if the
+ * node ID changes
+ *
+ * @return UuidInterface A UuidInterface instance that represents a
+ * version 2 UUID
+ */
+ public function uuid2(
+ int $localDomain,
+ ?IntegerObject $localIdentifier = null,
+ ?Hexadecimal $node = null,
+ ?int $clockSeq = null
+ ): UuidInterface;
+
+ /**
+ * Returns a version 3 (name-based) UUID based on the MD5 hash of a
+ * namespace ID and a name
+ *
+ * @param string|UuidInterface $ns The namespace (must be a valid UUID)
+ * @param string $name The name to use for creating a UUID
+ *
+ * @return UuidInterface A UuidInterface instance that represents a
+ * version 3 UUID
+ *
+ * @psalm-pure
+ */
+ public function uuid3($ns, string $name): UuidInterface;
+
+ /**
+ * Returns a version 4 (random) UUID
+ *
+ * @return UuidInterface A UuidInterface instance that represents a
+ * version 4 UUID
+ */
+ public function uuid4(): UuidInterface;
+
+ /**
+ * Returns a version 5 (name-based) UUID based on the SHA-1 hash of a
+ * namespace ID and a name
+ *
+ * @param string|UuidInterface $ns The namespace (must be a valid UUID)
+ * @param string $name The name to use for creating a UUID
+ *
+ * @return UuidInterface A UuidInterface instance that represents a
+ * version 5 UUID
+ *
+ * @psalm-pure
+ */
+ public function uuid5($ns, string $name): UuidInterface;
+
+ /**
+ * Returns a version 6 (ordered-time) UUID from a host ID, sequence number,
+ * and the current time
+ *
+ * @param Hexadecimal|null $node A 48-bit number representing the hardware
+ * address
+ * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
+ * that could arise when the clock is set backwards in time or if the
+ * node ID changes
+ *
+ * @return UuidInterface A UuidInterface instance that represents a
+ * version 6 UUID
+ */
+ public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface;
}
From b78bcda2d15463b8aa53d6339207e1ef77ea2253 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 12 Sep 2022 19:38:35 -0500
Subject: [PATCH 33/74] feat: move UuidV6 to the Rfc4122 namespace
---
psalm-baseline.xml | 170 +-------------------
src/Lazy/LazyUuidFromString.php | 2 +-
src/Nonstandard/UuidV6.php | 88 ++--------
src/Rfc4122/TimeTrait.php | 55 +++++++
src/Rfc4122/UuidBuilder.php | 1 -
src/Rfc4122/UuidV1.php | 36 +----
src/Rfc4122/UuidV2.php | 56 ++-----
src/Rfc4122/UuidV6.php | 29 ++++
src/Rfc4122/UuidV6ConverterTrait.php | 62 +++++++
src/Uuid.php | 12 +-
tests/Builder/FallbackBuilderTest.php | 2 +-
tests/Rfc4122/UuidBuilderTest.php | 11 +-
tests/Rfc4122/UuidV6Test.php | 222 ++++++++++++++++++++++++++
13 files changed, 423 insertions(+), 323 deletions(-)
create mode 100644 src/Rfc4122/TimeTrait.php
create mode 100644 src/Rfc4122/UuidV6.php
create mode 100644 src/Rfc4122/UuidV6ConverterTrait.php
create mode 100644 tests/Rfc4122/UuidV6Test.php
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index b5f529e..cf70c9a 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -1,5 +1,5 @@
-
+
DegradedUuid
@@ -16,12 +16,6 @@
$this
-
-
- Uuid::UUID_TYPE_TIME
- Uuid::UUID_TYPE_TIME
-
-
$this
@@ -44,14 +38,6 @@
BigNumberTimeConverter
-
-
- DegradedUuid
-
-
- Uuid
-
-
$calculator
@@ -73,20 +59,6 @@
uuid_parse
-
-
- Uuid::RESERVED_MICROSOFT
- Uuid::RFC_4122
-
-
-
-
- Guid
-
-
- parent::__construct($fields, $numberConverter, $codec, $timeConverter)
-
-
$this
@@ -95,24 +67,10 @@
-
- new UuidFactory()
-
-
- LazyUuidFromString
-
unserialize
-
-
- Uuid
-
-
- parent::__construct($fields, $numberConverter, $codec, $timeConverter)
-
-
$this
@@ -120,17 +78,6 @@
$this
-
-
- Uuid::UUID_TYPE_PEABODY
-
-
- UuidV6
-
-
- parent::__construct($fields, $numberConverter, $codec, $timeConverter)
-
-
shell_exec('id -g')
@@ -149,20 +96,10 @@
-
- Uuid::RFC_4122
- Uuid::UUID_TYPE_DCE_SECURITY
+
Uuid::UUID_TYPE_PEABODY
-
-
- NilUuid
-
-
- Uuid
-
-
$this
@@ -182,68 +119,10 @@
$this
-
-
- Uuid::UUID_TYPE_TIME
-
-
- UuidV1
-
-
- parent::__construct($fields, $numberConverter, $codec, $timeConverter)
-
-
-
-
- Uuid::UUID_TYPE_DCE_SECURITY
-
-
- UuidV2
-
-
- parent::__construct($fields, $numberConverter, $codec, $timeConverter)
-
-
-
-
- Uuid::UUID_TYPE_HASH_MD5
-
-
- UuidV3
-
-
- parent::__construct($fields, $numberConverter, $codec, $timeConverter)
-
-
-
-
- Uuid::UUID_TYPE_RANDOM
-
-
- UuidV4
-
-
- parent::__construct($fields, $numberConverter, $codec, $timeConverter)
-
-
-
-
- Uuid::UUID_TYPE_HASH_SHA1
-
-
- UuidV5
-
-
- parent::__construct($fields, $numberConverter, $codec, $timeConverter)
-
-
-
-
- Uuid::RESERVED_FUTURE
- Uuid::RESERVED_MICROSOFT
- Uuid::RESERVED_NCS
- Uuid::RFC_4122
-
+
+
+ NonstandardUuidV6
+
@@ -266,36 +145,6 @@
-
- new UuidFactory()
- new UuidFactory()
-
-
- Uuid
-
-
- fromDateTime
- getValidator
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- self::getFactory()
- uuid1
- uuid2
- uuid3
- uuid4
- uuid5
- uuid6
-
DeprecatedUuidMethodsTrait
@@ -312,13 +161,6 @@
-
- FeatureSet
- new FeatureSet()
-
-
- UuidFactory
-
$this->codec
$this->codec
diff --git a/src/Lazy/LazyUuidFromString.php b/src/Lazy/LazyUuidFromString.php
index 1ff1662..d2a169f 100644
--- a/src/Lazy/LazyUuidFromString.php
+++ b/src/Lazy/LazyUuidFromString.php
@@ -18,8 +18,8 @@ use DateTimeInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
use Ramsey\Uuid\Fields\FieldsInterface;
-use Ramsey\Uuid\Nonstandard\UuidV6;
use Ramsey\Uuid\Rfc4122\UuidV1;
+use Ramsey\Uuid\Rfc4122\UuidV6;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\UuidFactory;
diff --git a/src/Nonstandard/UuidV6.php b/src/Nonstandard/UuidV6.php
index 05586b3..8ea22fd 100644
--- a/src/Nonstandard/UuidV6.php
+++ b/src/Nonstandard/UuidV6.php
@@ -14,39 +14,34 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Nonstandard;
-use DateTimeImmutable;
-use DateTimeInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
-use Ramsey\Uuid\Exception\DateTimeException;
use Ramsey\Uuid\Exception\InvalidArgumentException;
-use Ramsey\Uuid\Lazy\LazyUuidFromString;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
+use Ramsey\Uuid\Rfc4122\TimeTrait;
use Ramsey\Uuid\Rfc4122\UuidInterface;
-use Ramsey\Uuid\Rfc4122\UuidV1;
+use Ramsey\Uuid\Rfc4122\UuidV6ConverterTrait;
use Ramsey\Uuid\Uuid;
-use Throwable;
-
-use function hex2bin;
-use function str_pad;
-use function substr;
-
-use const STR_PAD_LEFT;
/**
- * Ordered-time, or version 6, UUIDs include timestamp, clock sequence, and node
- * values that are combined into a 128-bit unsigned integer
+ * Reordered-time, or version 6, UUIDs include timestamp, clock sequence, and
+ * node values that are combined into a 128-bit unsigned integer
+ *
+ * @deprecated Use {@see \Ramsey\Uuid\Rfc4122\UuidV6} instead.
*
* @link https://github.com/uuid6/uuid6-ietf-draft UUID version 6 IETF draft
* @link http://gh.peabody.io/uuidv6/ "Version 6" UUIDs
*
* @psalm-immutable
*/
-final class UuidV6 extends Uuid implements UuidInterface
+class UuidV6 extends Uuid implements UuidInterface
{
+ use TimeTrait;
+ use UuidV6ConverterTrait;
+
/**
- * Creates a version 6 (time-based) UUID
+ * Creates a version 6 (reordered-time) UUID
*
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
@@ -62,7 +57,7 @@ final class UuidV6 extends Uuid implements UuidInterface
CodecInterface $codec,
TimeConverterInterface $timeConverter
) {
- if ($fields->getVersion() !== Uuid::UUID_TYPE_PEABODY) {
+ if ($fields->getVersion() !== Uuid::UUID_TYPE_REORDERED_TIME) {
throw new InvalidArgumentException(
'Fields used to create a UuidV6 must represent a '
. 'version 6 (ordered-time) UUID'
@@ -71,63 +66,4 @@ final class UuidV6 extends Uuid implements UuidInterface
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
-
- /**
- * Returns a DateTimeInterface object representing the timestamp associated
- * with the UUID
- *
- * @return DateTimeImmutable A PHP DateTimeImmutable instance representing
- * the timestamp of a version 6 UUID
- */
- public function getDateTime(): DateTimeInterface
- {
- $time = $this->timeConverter->convertTime($this->fields->getTimestamp());
-
- try {
- return new DateTimeImmutable(
- '@'
- . $time->getSeconds()->toString()
- . '.'
- . str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
- );
- } catch (Throwable $e) {
- throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
- }
- }
-
- /**
- * Converts this UUID into an instance of a version 1 UUID
- */
- public function toUuidV1(): UuidV1
- {
- $hex = $this->getHex()->toString();
- $hex = substr($hex, 7, 5)
- . substr($hex, 13, 3)
- . substr($hex, 3, 4)
- . '1' . substr($hex, 0, 3)
- . substr($hex, 16);
-
- /** @var LazyUuidFromString $uuid */
- $uuid = Uuid::fromBytes((string) hex2bin($hex));
-
- return $uuid->toUuidV1();
- }
-
- /**
- * Converts a version 1 UUID into an instance of a version 6 UUID
- */
- public static function fromUuidV1(UuidV1 $uuidV1): UuidV6
- {
- $hex = $uuidV1->getHex()->toString();
- $hex = substr($hex, 13, 3)
- . substr($hex, 8, 4)
- . substr($hex, 0, 5)
- . '6' . substr($hex, 5, 3)
- . substr($hex, 16);
-
- /** @var LazyUuidFromString $uuid */
- $uuid = Uuid::fromBytes((string) hex2bin($hex));
-
- return $uuid->toUuidV6();
- }
}
diff --git a/src/Rfc4122/TimeTrait.php b/src/Rfc4122/TimeTrait.php
new file mode 100644
index 0000000..5d939fa
--- /dev/null
+++ b/src/Rfc4122/TimeTrait.php
@@ -0,0 +1,55 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Rfc4122;
+
+use DateTimeImmutable;
+use DateTimeInterface;
+use Ramsey\Uuid\Exception\DateTimeException;
+use Throwable;
+
+use function str_pad;
+
+use const STR_PAD_LEFT;
+
+/**
+ * Provides common functionality for getting the time from a time-based UUID
+ *
+ * @psalm-immutable
+ */
+trait TimeTrait
+{
+ /**
+ * Returns a DateTimeInterface object representing the timestamp associated
+ * with the UUID
+ *
+ * @return DateTimeImmutable A PHP DateTimeImmutable instance representing
+ * the timestamp of a time-based UUID
+ */
+ public function getDateTime(): DateTimeInterface
+ {
+ $time = $this->timeConverter->convertTime($this->fields->getTimestamp());
+
+ try {
+ return new DateTimeImmutable(
+ '@'
+ . $time->getSeconds()->toString()
+ . '.'
+ . str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
+ );
+ } catch (Throwable $e) {
+ throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
+ }
+ }
+}
diff --git a/src/Rfc4122/UuidBuilder.php b/src/Rfc4122/UuidBuilder.php
index 736931a..df7ab30 100644
--- a/src/Rfc4122/UuidBuilder.php
+++ b/src/Rfc4122/UuidBuilder.php
@@ -20,7 +20,6 @@ use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
-use Ramsey\Uuid\Nonstandard\UuidV6;
use Ramsey\Uuid\Rfc4122\UuidInterface as Rfc4122UuidInterface;
use Ramsey\Uuid\UuidInterface;
use Throwable;
diff --git a/src/Rfc4122/UuidV1.php b/src/Rfc4122/UuidV1.php
index 764e42f..8a9cad2 100644
--- a/src/Rfc4122/UuidV1.php
+++ b/src/Rfc4122/UuidV1.php
@@ -14,20 +14,12 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Rfc4122;
-use DateTimeImmutable;
-use DateTimeInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
-use Ramsey\Uuid\Exception\DateTimeException;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Uuid;
-use Throwable;
-
-use function str_pad;
-
-use const STR_PAD_LEFT;
/**
* Time-based, or version 1, UUIDs include timestamp, clock sequence, and node
@@ -37,6 +29,8 @@ use const STR_PAD_LEFT;
*/
final class UuidV1 extends Uuid implements UuidInterface
{
+ use TimeTrait;
+
/**
* Creates a version 1 (time-based) UUID
*
@@ -63,30 +57,4 @@ final class UuidV1 extends Uuid implements UuidInterface
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
-
- /**
- * Returns a DateTimeInterface object representing the timestamp associated
- * with the UUID
- *
- * The timestamp value is only meaningful in a time-based UUID, which
- * has version type 1.
- *
- * @return DateTimeImmutable A PHP DateTimeImmutable instance representing
- * the timestamp of a version 1 UUID
- */
- public function getDateTime(): DateTimeInterface
- {
- $time = $this->timeConverter->convertTime($this->fields->getTimestamp());
-
- try {
- return new DateTimeImmutable(
- '@'
- . $time->getSeconds()->toString()
- . '.'
- . str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
- );
- } catch (Throwable $e) {
- throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
- }
- }
}
diff --git a/src/Rfc4122/UuidV2.php b/src/Rfc4122/UuidV2.php
index 74906f0..c8ccbe4 100644
--- a/src/Rfc4122/UuidV2.php
+++ b/src/Rfc4122/UuidV2.php
@@ -14,28 +14,33 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Rfc4122;
-use DateTimeImmutable;
-use DateTimeInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
-use Ramsey\Uuid\Exception\DateTimeException;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Uuid;
-use Throwable;
use function hexdec;
-use function str_pad;
-
-use const STR_PAD_LEFT;
/**
* DCE Security version, or version 2, UUIDs include local domain identifier,
* local ID for the specified domain, and node values that are combined into a
* 128-bit unsigned integer
*
+ * It is important to note that a version 2 UUID suffers from some loss of
+ * fidelity of the timestamp, due to replacing the time_low field with the
+ * local identifier. When constructing the timestamp value for date
+ * purposes, we replace the local identifier bits with zeros. As a result,
+ * the timestamp can be off by a range of 0 to 429.4967295 seconds (or 7
+ * minutes, 9 seconds, and 496730 microseconds).
+ *
+ * Astute observers might note this value directly corresponds to 2^32 - 1,
+ * or 0xffffffff. The local identifier is 32-bits, and we have set each of
+ * these bits to 0, so the maximum range of timestamp drift is 0x00000000
+ * to 0xffffffff (counted in 100-nanosecond intervals).
+ *
* @link https://publications.opengroup.org/c311 DCE 1.1: Authentication and Security Services
* @link https://publications.opengroup.org/c706 DCE 1.1: Remote Procedure Call
* @link https://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01 DCE 1.1: Auth & Sec, §5.2.1.1
@@ -47,6 +52,8 @@ use const STR_PAD_LEFT;
*/
final class UuidV2 extends Uuid implements UuidInterface
{
+ use TimeTrait;
+
/**
* Creates a version 2 (DCE Security) UUID
*
@@ -74,41 +81,6 @@ final class UuidV2 extends Uuid implements UuidInterface
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
- /**
- * Returns a DateTimeInterface object representing the timestamp associated
- * with the UUID
- *
- * It is important to note that a version 2 UUID suffers from some loss of
- * fidelity of the timestamp, due to replacing the time_low field with the
- * local identifier. When constructing the timestamp value for date
- * purposes, we replace the local identifier bits with zeros. As a result,
- * the timestamp can be off by a range of 0 to 429.4967295 seconds (or 7
- * minutes, 9 seconds, and 496730 microseconds).
- *
- * Astute observers might note this value directly corresponds to 2^32 - 1,
- * or 0xffffffff. The local identifier is 32-bits, and we have set each of
- * these bits to 0, so the maximum range of timestamp drift is 0x00000000
- * to 0xffffffff (counted in 100-nanosecond intervals).
- *
- * @return DateTimeImmutable A PHP DateTimeImmutable instance representing
- * the timestamp of a version 2 UUID
- */
- public function getDateTime(): DateTimeInterface
- {
- $time = $this->timeConverter->convertTime($this->fields->getTimestamp());
-
- try {
- return new DateTimeImmutable(
- '@'
- . $time->getSeconds()->toString()
- . '.'
- . str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
- );
- } catch (Throwable $e) {
- throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
- }
- }
-
/**
* Returns the local domain used to create this version 2 UUID
*/
diff --git a/src/Rfc4122/UuidV6.php b/src/Rfc4122/UuidV6.php
new file mode 100644
index 0000000..8b8c4b7
--- /dev/null
+++ b/src/Rfc4122/UuidV6.php
@@ -0,0 +1,29 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Rfc4122;
+
+use Ramsey\Uuid\Nonstandard\UuidV6 as NonstandardUuidV6;
+
+/**
+ * Reordered-time, or version 6, UUIDs include timestamp, clock sequence, and
+ * node values that are combined into a 128-bit unsigned integer
+ *
+ * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6
+ *
+ * @psalm-immutable
+ */
+final class UuidV6 extends NonstandardUuidV6 implements UuidInterface
+{
+}
diff --git a/src/Rfc4122/UuidV6ConverterTrait.php b/src/Rfc4122/UuidV6ConverterTrait.php
new file mode 100644
index 0000000..cca0cff
--- /dev/null
+++ b/src/Rfc4122/UuidV6ConverterTrait.php
@@ -0,0 +1,62 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Rfc4122;
+
+use Ramsey\Uuid\Lazy\LazyUuidFromString;
+use Ramsey\Uuid\Uuid;
+
+/**
+ * Provides functionality to convert between UuidV1 and UuidV6
+ *
+ * @psalm-immutable
+ */
+trait UuidV6ConverterTrait
+{
+ /**
+ * Converts this UUID into an instance of a version 1 UUID
+ */
+ public function toUuidV1(): UuidV1
+ {
+ $hex = $this->getHex()->toString();
+ $hex = substr($hex, 7, 5)
+ . substr($hex, 13, 3)
+ . substr($hex, 3, 4)
+ . '1' . substr($hex, 0, 3)
+ . substr($hex, 16);
+
+ /** @var LazyUuidFromString $uuid */
+ $uuid = Uuid::fromBytes((string) hex2bin($hex));
+
+ return $uuid->toUuidV1();
+ }
+
+ /**
+ * Converts a version 1 UUID into an instance of a version 6 UUID
+ */
+ public static function fromUuidV1(UuidV1 $uuidV1): UuidV6
+ {
+ $hex = $uuidV1->getHex()->toString();
+ $hex = substr($hex, 13, 3)
+ . substr($hex, 8, 4)
+ . substr($hex, 0, 5)
+ . '6' . substr($hex, 5, 3)
+ . substr($hex, 16);
+
+ /** @var LazyUuidFromString $uuid */
+ $uuid = Uuid::fromBytes((string) hex2bin($hex));
+
+ return $uuid->toUuidV6();
+ }
+}
diff --git a/src/Uuid.php b/src/Uuid.php
index 019cec8..3a7c8ec 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -156,19 +156,25 @@ class Uuid implements UuidInterface
public const UUID_TYPE_HASH_SHA1 = 5;
/**
- * Version 6 (ordered-time) UUID
+ * Version 6 (reordered-time) UUID
*
* This is named `UUID_TYPE_PEABODY`, since the specification is still in
* draft form, and the primary author/editor's name is Brad Peabody.
*
- * @deprecated The Ramsey\Uuid\Version enum will replace this constant in
- * ramsey/uuid version 5.
+ * @deprecated Use {@see Uuid::UUID_TYPE_REORDERED_TIME} instead.
*
* @link https://github.com/uuid6/uuid6-ietf-draft UUID version 6 IETF draft
* @link http://gh.peabody.io/uuidv6/ "Version 6" UUIDs
*/
public const UUID_TYPE_PEABODY = 6;
+ /**
+ * Version 6 (reordered-time) UUID
+ *
+ * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6
+ */
+ public const UUID_TYPE_REORDERED_TIME = 6;
+
/**
* DCE Security principal domain
*
diff --git a/tests/Builder/FallbackBuilderTest.php b/tests/Builder/FallbackBuilderTest.php
index 7fe2adb..a601ee6 100644
--- a/tests/Builder/FallbackBuilderTest.php
+++ b/tests/Builder/FallbackBuilderTest.php
@@ -18,10 +18,10 @@ use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\Guid\GuidBuilder;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
-use Ramsey\Uuid\Nonstandard\UuidV6;
use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
use Ramsey\Uuid\Rfc4122\UuidV1;
use Ramsey\Uuid\Rfc4122\UuidV2;
+use Ramsey\Uuid\Rfc4122\UuidV6;
use Ramsey\Uuid\Test\TestCase;
class FallbackBuilderTest extends TestCase
diff --git a/tests/Rfc4122/UuidBuilderTest.php b/tests/Rfc4122/UuidBuilderTest.php
index 9e39067..e234fc3 100644
--- a/tests/Rfc4122/UuidBuilderTest.php
+++ b/tests/Rfc4122/UuidBuilderTest.php
@@ -10,7 +10,7 @@ use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\Math\BrickMathCalculator;
-use Ramsey\Uuid\Nonstandard\UuidV6;
+use Ramsey\Uuid\Nonstandard\UuidV6 as NonstandardUuidV6;
use Ramsey\Uuid\Rfc4122\Fields;
use Ramsey\Uuid\Rfc4122\FieldsInterface;
use Ramsey\Uuid\Rfc4122\UuidBuilder;
@@ -19,6 +19,7 @@ use Ramsey\Uuid\Rfc4122\UuidV2;
use Ramsey\Uuid\Rfc4122\UuidV3;
use Ramsey\Uuid\Rfc4122\UuidV4;
use Ramsey\Uuid\Rfc4122\UuidV5;
+use Ramsey\Uuid\Rfc4122\UuidV6;
use Ramsey\Uuid\Test\TestCase;
use function hex2bin;
@@ -86,6 +87,14 @@ class UuidBuilderTest extends TestCase
'expectedClass' => UuidV6::class,
'expectedVersion' => 6,
],
+
+ // The same UUIDv6 will also be of the expected class type
+ // \Ramsey\Uuid\Nonstandard\UuidV6.
+ [
+ 'uuid' => 'ff6f8cb0-c57d-61e1-9b21-0800200c9a66',
+ 'expectedClass' => NonstandardUuidV6::class,
+ 'expectedVersion' => 6,
+ ],
];
}
diff --git a/tests/Rfc4122/UuidV6Test.php b/tests/Rfc4122/UuidV6Test.php
new file mode 100644
index 0000000..1c72528
--- /dev/null
+++ b/tests/Rfc4122/UuidV6Test.php
@@ -0,0 +1,222 @@
+ $version,
+ ]);
+
+ $numberConverter = Mockery::mock(NumberConverterInterface::class);
+ $codec = Mockery::mock(CodecInterface::class);
+ $timeConverter = Mockery::mock(TimeConverterInterface::class);
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage(
+ 'Fields used to create a UuidV6 must represent a '
+ . 'version 6 (ordered-time) UUID'
+ );
+
+ new UuidV6($fields, $numberConverter, $codec, $timeConverter);
+ }
+
+ /**
+ * @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification
+ */
+ public function provideTestVersions(): array
+ {
+ return [
+ ['version' => 0],
+ ['version' => 1],
+ ['version' => 2],
+ ['version' => 3],
+ ['version' => 4],
+ ['version' => 5],
+ ['version' => 7],
+ ['version' => 8],
+ ['version' => 9],
+ ];
+ }
+
+ /**
+ * @param non-empty-string $uuid
+ *
+ * @dataProvider provideUuidV6WithOddMicroseconds
+ */
+ public function testGetDateTimeProperlyHandlesLongMicroseconds(string $uuid, string $expected): void
+ {
+ /** @var UuidV6 $object */
+ $object = Uuid::fromString($uuid);
+
+ $date = $object->getDateTime();
+
+ $this->assertInstanceOf(DateTimeImmutable::class, $date);
+ $this->assertSame($expected, $date->format('U.u'));
+ }
+
+ /**
+ * @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification
+ */
+ public function provideUuidV6WithOddMicroseconds(): array
+ {
+ return [
+ [
+ 'uuid' => '1b21dd21-4814-6000-9669-00007ffffffe',
+ 'expected' => '1.677722',
+ ],
+ [
+ 'uuid' => '1b21dd21-3714-6000-9669-00007ffffffe',
+ 'expected' => '0.104858',
+ ],
+ [
+ 'uuid' => '1b21dd21-3713-6000-9669-00007ffffffe',
+ 'expected' => '0.105267',
+ ],
+ [
+ 'uuid' => '1b21dd21-2e8a-6980-8d4f-acde48001122',
+ 'expected' => '-1.000000',
+ ],
+ ];
+ }
+
+ /**
+ * @param non-empty-string $uuidv6
+ * @param non-empty-string $uuidv1
+ *
+ * @dataProvider provideUuidV1UuidV6Equivalents
+ */
+ public function testToUuidV1(string $uuidv6, string $uuidv1): void
+ {
+ /** @var UuidV6 $uuid6 */
+ $uuid6 = Uuid::fromString($uuidv6);
+ $uuid1 = $uuid6->toUuidV1();
+
+ $this->assertSame($uuidv6, $uuid6->toString());
+ $this->assertSame($uuidv1, $uuid1->toString());
+
+ $this->assertSame(
+ $uuid6->getDateTime()->format('U.u'),
+ $uuid1->getDateTime()->format('U.u')
+ );
+ }
+
+ /**
+ * @param non-empty-string $uuidv6
+ * @param non-empty-string $uuidv1
+ *
+ * @dataProvider provideUuidV1UuidV6Equivalents
+ */
+ public function testFromUuidV1(string $uuidv6, string $uuidv1): void
+ {
+ /** @var LazyUuidFromString $uuid */
+ $uuid = Uuid::fromString($uuidv1);
+ $uuid1 = $uuid->toUuidV1();
+ $uuid6 = UuidV6::fromUuidV1($uuid1);
+
+ $this->assertSame($uuidv1, $uuid1->toString());
+ $this->assertSame($uuidv6, $uuid6->toString());
+
+ $this->assertSame(
+ $uuid1->getDateTime()->format('U.u'),
+ $uuid6->getDateTime()->format('U.u')
+ );
+ }
+
+ /**
+ * @phpcsSuppress SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingTraversableTypeHintSpecification
+ */
+ public function provideUuidV1UuidV6Equivalents(): array
+ {
+ return [
+ [
+ 'uuidv6' => '1b21dd21-4814-6000-9669-00007ffffffe',
+ 'uuidv1' => '14814000-1dd2-11b2-9669-00007ffffffe',
+ ],
+ [
+ 'uuidv6' => '1b21dd21-3714-6000-9669-00007ffffffe',
+ 'uuidv1' => '13714000-1dd2-11b2-9669-00007ffffffe',
+ ],
+ [
+ 'uuidv6' => '1b21dd21-3713-6000-9669-00007ffffffe',
+ 'uuidv1' => '13713000-1dd2-11b2-9669-00007ffffffe',
+ ],
+ [
+ 'uuidv6' => '1b21dd21-2e8a-6980-8d4f-acde48001122',
+ 'uuidv1' => '12e8a980-1dd2-11b2-8d4f-acde48001122',
+ ],
+ ];
+ }
+
+ public function testGetDateTimeThrowsException(): void
+ {
+ $fields = Mockery::mock(FieldsInterface::class, [
+ 'getVersion' => 6,
+ 'getTimestamp' => new Hexadecimal('0'),
+ ]);
+
+ $numberConverter = Mockery::mock(NumberConverterInterface::class);
+ $codec = Mockery::mock(CodecInterface::class);
+
+ $timeConverter = Mockery::mock(TimeConverterInterface::class, [
+ 'convertTime' => new Time('0', '1234567'),
+ ]);
+
+ $uuid = new UuidV6($fields, $numberConverter, $codec, $timeConverter);
+
+ $this->expectException(DateTimeException::class);
+
+ $uuid->getDateTime();
+ }
+
+ /**
+ * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#appendix-B.1
+ */
+ public function testUsingDraftPeabodyUuidV6TestVector(): void
+ {
+ $testVector = '1EC9414C-232A-6B00-B3C8-9E6BDECED846';
+
+ /** @var UuidV6 $uuidv6 */
+ $uuidv6 = Uuid::fromString($testVector);
+
+ $uuidv1 = $uuidv6->toUuidV1();
+
+ /** @var FieldsInterface $fields */
+ $fields = $uuidv6->getFields();
+
+ $this->assertSame('1ec9414c', $fields->getTimeLow()->toString());
+ $this->assertSame('232a', $fields->getTimeMid()->toString());
+ $this->assertSame('6b00', $fields->getTimeHiAndVersion()->toString());
+ $this->assertSame('b3', $fields->getClockSeqHiAndReserved()->toString());
+ $this->assertSame('c8', $fields->getClockSeqLow()->toString());
+ $this->assertSame('9e6bdeced846', $fields->getNode()->toString());
+ $this->assertSame(1645557742, $uuidv6->getDateTime()->getTimestamp());
+
+ $this->assertSame(
+ 'c232ab00-9414-11ec-b3c8-9e6bdeced846',
+ $uuidv1->toString(),
+ );
+ }
+}
From 7d1400b90acd94b290c057534b958d97cc129650 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 12 Sep 2022 20:46:34 -0500
Subject: [PATCH 34/74] doc: update for Rfc4122\UuidV6
---
docs/customize.rst | 4 +-
docs/customize/ordered-time-codec.rst | 10 +-
docs/database.rst | 7 +-
docs/nonstandard.rst | 4 +-
docs/nonstandard/version6.rst | 214 ++----------------------
docs/quickstart.rst | 2 +-
docs/reference.rst | 3 +-
docs/reference/helper.rst | 4 +-
docs/reference/nonstandard-uuidv6.rst | 18 +-
docs/reference/rfc4122-uuidv1.rst | 2 +-
docs/reference/rfc4122-uuidv6.rst | 31 ++++
docs/reference/uuid.rst | 12 +-
docs/reference/uuidfactoryinterface.rst | 6 +-
docs/rfc4122.rst | 8 +-
docs/rfc4122/version1.rst | 12 +-
docs/rfc4122/version5.rst | 4 +-
docs/rfc4122/version6.rst | 207 +++++++++++++++++++++++
17 files changed, 302 insertions(+), 246 deletions(-)
create mode 100644 docs/reference/rfc4122-uuidv6.rst
create mode 100644 docs/rfc4122/version6.rst
diff --git a/docs/customize.rst b/docs/customize.rst
index 1dc0c19..a67fbc0 100644
--- a/docs/customize.rst
+++ b/docs/customize.rst
@@ -22,8 +22,8 @@ to replace just about any `builder`_, `codec`_, `converter`_, `generator`_,
Ordered-time Codec
The ordered-time codec exists to rearrange the bytes of a version 1,
- time-based UUID so that the timestamp portion of the UUID is monotonically
- increasing. To learn more, see :ref:`customize.ordered-time-codec`.
+ Gregorian time UUID so that the timestamp portion of the UUID is
+ monotonically increasing. To learn more, see :ref:`customize.ordered-time-codec`.
Timestamp-first COMB Codec
The timestamp-first COMB codec replaces part of a version 4, random UUID
diff --git a/docs/customize/ordered-time-codec.rst b/docs/customize/ordered-time-codec.rst
index bad166f..b71a7eb 100644
--- a/docs/customize/ordered-time-codec.rst
+++ b/docs/customize/ordered-time-codec.rst
@@ -6,8 +6,8 @@ Ordered-time Codec
.. hint::
- :ref:`Version 6, ordered-time UUIDs ` are a proposed
- new version of UUID that take the place of ordered time UUIDs.
+ :ref:`Version 6, reordered time UUIDs ` are a
+ new version of UUID that take the place of ordered-time UUIDs.
UUIDs arrange their bytes according to the standard recommended by `RFC 4122`_.
Unfortunately, this means the bytes aren't in an arrangement that supports
@@ -15,9 +15,9 @@ sorting by creation time or an otherwise incrementing value. The Percona
article, "`Storing UUID Values in MySQL`_," explains at length the problems this
can cause. It also recommends a solution: the *ordered-time UUID*.
-RFC 4122 version 1, time-based UUIDs rearrange the bytes of the time fields so
-that the lowest bytes appear first, the middle bytes are next, and the highest
-bytes come last. Logical sorting is not possible with this arrangement.
+RFC 4122 version 1, Gregorian time UUIDs rearrange the bytes of the time fields
+so that the lowest bytes appear first, the middle bytes are next, and the
+highest bytes come last. Logical sorting is not possible with this arrangement.
An ordered-time UUID is a version 1 UUID with the time fields arranged in
logical order so that the UUIDs can be sorted by creation time. These UUIDs are
diff --git a/docs/database.rst b/docs/database.rst
index 3607dfd..9459862 100644
--- a/docs/database.rst
+++ b/docs/database.rst
@@ -242,7 +242,7 @@ will become slower and slower.
To minimize these problems, two solutions have been devised:
1. Timestamp first COMBs
-2. Ordered Time UUIDs
+2. Ordered-time UUIDs
:ref:`customize.timestamp-first-comb-codec` explains the first solution and how
to use ramsey/uuid to implement it, while :ref:`customize.ordered-time-codec`
@@ -250,8 +250,8 @@ explains how to use ramsey/uuid to implement the second solution.
.. hint::
- :ref:`Version 6, ordered-time UUIDs ` are a proposed
- new version of UUID that take the place of ordered time UUIDs.
+ :ref:`Version 6, reordered time UUIDs ` are a
+ new version of UUID that take the place of ordered-time UUIDs.
.. _ramsey/uuid-doctrine: https://github.com/ramsey/uuid-doctrine
@@ -259,4 +259,3 @@ explains how to use ramsey/uuid to implement the second solution.
.. _MariaDB: https://mariadb.org
.. _PHP Data Objects (PDO): https://www.php.net/pdo
.. _Storing UUID Values in MySQL: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
-.. _Version 6, ordered-time UUIDs: nonstandard.version6
diff --git a/docs/nonstandard.rst b/docs/nonstandard.rst
index b35002e..83ed900 100644
--- a/docs/nonstandard.rst
+++ b/docs/nonstandard.rst
@@ -20,8 +20,8 @@ completely random and do not follow any rules.
For these cases, ramsey/uuid provides a special functionality to handle these
alternate, nonstandard forms.
-Version 6: Ordered-time
- This is a proposed version of UUID that combines the features of a
+Version 6: Reordered Time
+ This is a new version of UUID that combines the features of a
:ref:`version 1 UUID ` with a *monotonically increasing*
UUID. For more details, see :ref:`nonstandard.version6`.
diff --git a/docs/nonstandard/version6.rst b/docs/nonstandard/version6.rst
index aca5443..c45482e 100644
--- a/docs/nonstandard/version6.rst
+++ b/docs/nonstandard/version6.rst
@@ -1,209 +1,17 @@
.. _nonstandard.version6:
-=======================
-Version 6: Ordered-Time
-=======================
+=========================
+Version 6: Reordered Time
+=========================
-.. admonition:: Experimental
- :class: warning
+.. attention::
- Version 6, ordered-time UUIDs are an experimental feature based on an
- `Internet-Draft under review`_ at the IETF. While the basic layout is not
- expected to change, be aware that the draft is a moving target. If there
- are significant changes to the layout, ramsey/uuid will attempt to maintain
- backward compatibility but cannot guarantee it.
+ This documentation has moved to :ref:`RFC 4122 UUIDs: Version 6: Reordered
+ Time `.
-Version 6 UUIDs solve `two problems that have long existed`_ with the use of
-:ref:`version 1 ` UUIDs:
+ Version 6 UUIDs have been promoted to the ``Rfc4122`` namespace. While still
+ in draft form, the version 6 format is not expected to change in any way
+ that breaks compatibility.
-1. Scattered database records
-2. Inability to sort by an identifier in a meaningful way (i.e., insert order)
-
-To overcome these issues, we need the ability to generate UUIDs that are
-*monotonically increasing* while still providing all the benefits of version
-1 UUIDs.
-
-Version 6 UUIDs do this by storing the time in standard byte order, instead of
-breaking it up and rearranging the time bytes, according to the `RFC 4122`_
-definition. All other fields remain the same, and the version maintains its
-position, according to RFC 4122.
-
-In all other ways, version 6 UUIDs function like version 1 UUIDs.
-
-.. tip::
-
- Prior to version 4.0.0, ramsey/uuid provided a solution for this with the
- :ref:`ordered-time codec `. Use of the
- ordered-time codec is still valid and acceptable. However, you may replace
- UUIDs generated using the ordered-time codec with version 6 UUIDs. Keep
- reading to find out how.
-
-.. code-block:: php
- :caption: Generate a version 6, ordered-time UUID
- :name: nonstandard.version6.example
-
- use Ramsey\Uuid\Uuid;
-
- $uuid = Uuid::uuid6();
-
- printf(
- "UUID: %s\nVersion: %d\nDate: %s\nNode: %s\n",
- $uuid->toString(),
- $uuid->getFields()->getVersion(),
- $uuid->getDateTime()->format('r'),
- $uuid->getFields()->getNode()->toString()
- );
-
-This will generate a version 6 UUID and print out its string representation, the
-time the UUID was created, and the node used to create the UUID.
-
-It will look something like this:
-
-.. code-block:: text
-
- UUID: 1ea60f56-b67b-61fc-829a-0242ac130003
- Version: 6
- Date: Sun, 08 Mar 2020 04:29:37 +0000
- Node: 0242ac130003
-
-You may provide custom values for version 6 UUIDs, including node and clock
-sequence.
-
-.. code-block:: php
- :caption: Provide custom node and clock sequence to create a version 6,
- ordered-time UUID
- :name: nonstandard.version6.custom-example
-
- use Ramsey\Uuid\Provider\Node\StaticNodeProvider;
- use Ramsey\Uuid\Type\Hexadecimal;
- use Ramsey\Uuid\Uuid;
-
- $nodeProvider = new StaticNodeProvider(new Hexadecimal('121212121212'));
- $clockSequence = 16383;
-
- $uuid = Uuid::uuid6($nodeProvider->getNode(), $clockSequence);
-
-.. tip::
-
- Version 6 UUIDs generated in ramsey/uuid are instances of UuidV6. Check out
- the :php:class:`Ramsey\\Uuid\\Nonstandard\\UuidV6` API documentation to
- learn more about what you can do with a UuidV6 instance.
-
-
-.. _nonstandard.version6.nodes:
-
-Custom and Random Nodes
-#######################
-
-In the :ref:`example above `, we provided a
-custom node when generating a version 6 UUID. You may also generate random
-node values.
-
-To learn more, see the :ref:`rfc4122.version1.custom` and
-:ref:`rfc4122.version1.random` sections under :ref:`rfc4122.version1`.
-
-
-.. _nonstandard.version6.clock:
-
-Clock Sequence
-##############
-
-In a version 6 UUID, the clock sequence serves the same purpose as in a version
-1 UUID. See :ref:`rfc4122.version1.clock` to learn more.
-
-
-.. _nonstandard.version6.version1-conversion:
-
-Version 1-to-6 Conversion
-#########################
-
-It is possible to convert back-and-forth between version 6 and version 1 UUIDs.
-
-.. code-block:: php
- :caption: Convert a version 1 UUID to a version 6 UUID
- :name: nonstandard.version6.convert-version1-example
-
- use Ramsey\Uuid\Nonstandard\UuidV6;
- use Ramsey\Uuid\Rfc4122\UuidV1;
- use Ramsey\Uuid\Uuid;
-
- $uuid1 = Uuid::fromString('3960c5d8-60f8-11ea-bc55-0242ac130003');
-
- if ($uuid1 instanceof UuidV1) {
- $uuid6 = UuidV6::fromUuidV1($uuid1);
- }
-
-.. code-block:: php
- :caption: Convert a version 6 UUID to a version 1 UUID
- :name: nonstandard.version6.convert-version6-example
-
- use Ramsey\Uuid\Nonstandard\UuidV6;
- use Ramsey\Uuid\Uuid;
-
- $uuid6 = Uuid::fromString('1ea60f83-960c-65d8-bc55-0242ac130003');
-
- if ($uuid6 instanceof UuidV6) {
- $uuid1 = $uuid6->toUuidV1();
- }
-
-
-.. _nonstandard.version6.ordered-time-conversion:
-
-Ordered-time to Version 6 Conversion
-####################################
-
-You may convert UUIDs previously generated and stored using the
-:ref:`ordered-time codec ` into version 6 UUIDs.
-
-.. caution::
-
- If you perform this conversion, the bytes and string representation of your
- UUIDs will change. This will break any software that expects your
- identifiers to be fixed.
-
-.. code-block:: php
- :caption: Convert an ordered-time codec encoded UUID to a version 6 UUID
- :name: nonstandard.version6.convert-ordered-time-example
-
- use Ramsey\Uuid\Codec\OrderedTimeCodec;
- use Ramsey\Uuid\Nonstandard\UuidV6;
- use Ramsey\Uuid\Rfc4122\UuidV1;
- use Ramsey\Uuid\UuidFactory;
-
- // The bytes of a version 1 UUID previously stored in some datastore
- // after encoding to bytes with the OrderedTimeCodec.
- $bytes = hex2bin('11ea60faf17c8af6ad23acde48001122');
-
- $factory = new UuidFactory();
- $codec = new OrderedTimeCodec($factory->getUuidBuilder());
-
- $factory->setCodec($codec);
-
- $orderedTimeUuid = $factory->fromBytes($bytes);
-
- if ($orderedTimeUuid instanceof UuidV1) {
- $uuid6 = UuidV6::fromUuidV1($orderedTimeUuid);
- }
-
-
-.. _nonstandard.version6.privacy:
-
-Privacy Concerns
-################
-
-Like :ref:`version 1 UUIDs `, version 6 UUIDs use a MAC
-address from a local hardware network interface. This means it is possible to
-uniquely identify the machine on which a version 6 UUID was created.
-
-If the value provided by the timestamp of a version 6 UUID is important to you,
-but you do not wish to expose the interface address of any of your local
-machines, see :ref:`nonstandard.version6.nodes`.
-
-If you do not need an identifier with a node value embedded in it, but you still
-need the benefit of a monotonically increasing unique identifier, see
-:ref:`customize.timestamp-first-comb-codec`.
-
-
-.. _Internet-Draft under review: https://tools.ietf.org/html/draft-peabody-dispatch-new-uuid-format
-.. _two problems that have long existed: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
-.. _RFC 4122: https://tools.ietf.org/html/rfc4122
+ The :php:class:`Ramsey\\Uuid\\Nonstandard\\UuidV6` class is deprecated in
+ favor of :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV6`.
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index 6cd310c..871fd1c 100644
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -96,7 +96,7 @@ library.
* - :php:meth:`Uuid::uuid5() `
- This generates a :ref:`rfc4122.version5` UUID.
* - :php:meth:`Uuid::uuid6() `
- - This generates a :ref:`nonstandard.version6` UUID.
+ - This generates a :ref:`rfc4122.version6` UUID.
* - :php:meth:`Uuid::isValid() `
- Checks whether a string is a valid UUID.
* - :php:meth:`Uuid::fromString() `
diff --git a/docs/reference.rst b/docs/reference.rst
index 00e27b6..b04e1bd 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -17,11 +17,12 @@ Reference
reference/rfc4122-uuidv3
reference/rfc4122-uuidv4
reference/rfc4122-uuidv5
- reference/nonstandard-uuidv6
+ reference/rfc4122-uuidv6
reference/guid-fields
reference/guid-guid
reference/nonstandard-fields
reference/nonstandard-uuid
+ reference/nonstandard-uuidv6
reference/uuidfactoryinterface
reference/types
reference/exceptions
diff --git a/docs/reference/helper.rst b/docs/reference/helper.rst
index 9c410e1..6ab3aff 100644
--- a/docs/reference/helper.rst
+++ b/docs/reference/helper.rst
@@ -9,7 +9,7 @@ only the string standard representation of a UUID.
.. php:function:: Ramsey\\Uuid\\v1([$node[, $clockSeq]])
- Generates a string standard representation of a version 1, time-based UUID.
+ Generates a string standard representation of a version 1, Gregorian time UUID.
:param Ramsey\\Uuid\\Type\\Hexadecimal|null $node: An optional hexadecimal node to use
:param int|null $clockSeq: An optional clock sequence to use
@@ -54,7 +54,7 @@ only the string standard representation of a UUID.
.. php:function:: Ramsey\\Uuid\\v6([$node[, $clockSeq]])
- Generates a string standard representation of a version 6, ordered-time UUID.
+ Generates a string standard representation of a version 6, reordered time UUID.
:param Ramsey\\Uuid\\Type\\Hexadecimal|null $node: An optional hexadecimal node to use
:param int|null $clockSeq: An optional clock sequence to use
diff --git a/docs/reference/nonstandard-uuidv6.rst b/docs/reference/nonstandard-uuidv6.rst
index cc77067..9ca743e 100644
--- a/docs/reference/nonstandard-uuidv6.rst
+++ b/docs/reference/nonstandard-uuidv6.rst
@@ -8,13 +8,16 @@ Nonstandard\\UuidV6
.. php:class:: UuidV6
+ .. attention::
+
+ :php:class:`Ramsey\\Uuid\\Nonstandard\\UuidV6` is deprecated in favor of
+ :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV6`. Please migrate any code
+ using ``Nonstandard\UuidV6`` to ``Rfc4122\UuidV6``. The interface is
+ otherwise identical.
+
Implements :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface`.
- While in the Nonstandard sub-namespace, UuidV6 implements the same interface
- as the RFC 4122 UUIDs. This is because the definition for version 6 UUIDs is
- `currently in draft form`_, with the intent to update RFC 4122.
-
- UuidV6 represents a :ref:`version 6, ordered-time UUID
+ UuidV6 represents a :ref:`version 6, reordered time UUID
`. In addition to providing the methods defined on the
interface, this class additionally provides the following methods.
@@ -32,7 +35,4 @@ Nonstandard\\UuidV6
:param Ramsey\\Uuid\\Rfc4122\\UuidV1 $uuidV1: A version 1 UUID
:returns: A version 6 UUID, converted from the given version 1 UUID
- :returntype: Ramsey\\Uuid\\Nonstandard\\UuidV6
-
-
-.. _currently in draft form: https://tools.ietf.org/html/draft-peabody-dispatch-new-uuid-format-00
+ :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV6
diff --git a/docs/reference/rfc4122-uuidv1.rst b/docs/reference/rfc4122-uuidv1.rst
index c28c27c..985fd5b 100644
--- a/docs/reference/rfc4122-uuidv1.rst
+++ b/docs/reference/rfc4122-uuidv1.rst
@@ -10,7 +10,7 @@ Rfc4122\\UuidV1
Implements :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface`.
- UuidV1 represents a :ref:`version 1, time-based UUID `.
+ UuidV1 represents a :ref:`version 1, Gregorian time UUID `.
In addition to providing the methods defined on the interface, this class
additionally provides the following methods.
diff --git a/docs/reference/rfc4122-uuidv6.rst b/docs/reference/rfc4122-uuidv6.rst
new file mode 100644
index 0000000..0b15f7e
--- /dev/null
+++ b/docs/reference/rfc4122-uuidv6.rst
@@ -0,0 +1,31 @@
+.. _reference.rfc4122.uuidv6:
+
+===============
+Rfc4122\\UuidV6
+===============
+
+.. php:namespace:: Ramsey\Uuid\Rfc4122
+
+.. php:class:: UuidV6
+
+ Implements :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface`.
+
+ UuidV6 represents a :ref:`version 6, reordered time UUID
+ `. In addition to providing the methods defined on the
+ interface, this class additionally provides the following methods.
+
+ .. php:method:: getDateTime()
+
+ :returns: A date object representing the timestamp associated with the UUID
+ :returntype: ``\DateTimeInterface``
+
+ .. php:method:: toUuidV1()
+
+ :returns: A version 1 UUID, converted from this version 6 UUID
+ :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV1
+
+ .. php:staticmethod:: fromUuidV1()
+
+ :param Ramsey\\Uuid\\Rfc4122\\UuidV1 $uuidV1: A version 1 UUID
+ :returns: A version 6 UUID, converted from the given version 1 UUID
+ :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV6
diff --git a/docs/reference/uuid.rst b/docs/reference/uuid.rst
index f3c2f32..447dbad 100644
--- a/docs/reference/uuid.rst
+++ b/docs/reference/uuid.rst
@@ -32,9 +32,13 @@ the ramsey/uuid library.
:ref:`rfc4122.version5` UUID.
+ .. php:const:: UUID_TYPE_REORDERED_TIME
+
+ :ref:`rfc4122.version6` UUID.
+
.. php:const:: UUID_TYPE_PEABODY
- :ref:`nonstandard.version6` UUID.
+ *Deprecated.* Use :php:const:`Uuid::UUID_TYPE_REORDERED_TIME` instead.
.. php:const:: NAMESPACE_DNS
@@ -87,7 +91,7 @@ the ramsey/uuid library.
.. php:staticmethod:: uuid1([$node[, $clockSeq]])
- Generates a version 1, time-based UUID. See :ref:`rfc4122.version1`.
+ Generates a version 1, Gregorian time UUID. See :ref:`rfc4122.version1`.
:param Ramsey\\Uuid\\Type\\Hexadecimal|null $node: An optional hexadecimal node to use
:param int|null $clockSeq: An optional clock sequence to use
@@ -132,12 +136,12 @@ the ramsey/uuid library.
.. php:staticmethod:: uuid6([$node[, $clockSeq]])
- Generates a version 6, ordered-time UUID. See :ref:`nonstandard.version6`.
+ Generates a version 6, reordered time UUID. See :ref:`rfc4122.version6`.
:param Ramsey\\Uuid\\Type\\Hexadecimal|null $node: An optional hexadecimal node to use
:param int|null $clockSeq: An optional clock sequence to use
:returns: A version 6 UUID
- :returntype: Ramsey\\Uuid\\Nonstandard\\UuidV6
+ :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV6
.. php:staticmethod:: fromString($uuid)
diff --git a/docs/reference/uuidfactoryinterface.rst b/docs/reference/uuidfactoryinterface.rst
index 842f71d..c68a61d 100644
--- a/docs/reference/uuidfactoryinterface.rst
+++ b/docs/reference/uuidfactoryinterface.rst
@@ -16,7 +16,7 @@ UuidFactoryInterface
.. php:method:: uuid1([$node[, $clockSeq]])
- Generates a version 1, time-based UUID. See :ref:`rfc4122.version1`.
+ Generates a version 1, Gregorian time UUID. See :ref:`rfc4122.version1`.
:param Ramsey\\Uuid\\Type\\Hexadecimal|null $node: An optional hexadecimal node to use
:param int|null $clockSeq: An optional clock sequence to use
@@ -61,12 +61,12 @@ UuidFactoryInterface
.. php:method:: uuid6([$node[, $clockSeq]])
- Generates a version 6, ordered-time UUID. See :ref:`nonstandard.version6`.
+ Generates a version 6, reordered time UUID. See :ref:`rfc4122.version6`.
:param Ramsey\\Uuid\\Type\\Hexadecimal|null $node: An optional hexadecimal node to use
:param int|null $clockSeq: An optional clock sequence to use
:returns: A version 6 UUID
- :returntype: Ramsey\\Uuid\\Nonstandard\\UuidV6
+ :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV6
.. php:method:: fromString($uuid)
diff --git a/docs/rfc4122.rst b/docs/rfc4122.rst
index ec74b59..d6c19d6 100644
--- a/docs/rfc4122.rst
+++ b/docs/rfc4122.rst
@@ -13,13 +13,14 @@ RFC 4122 UUIDs
rfc4122/version3
rfc4122/version4
rfc4122/version5
+ rfc4122/version6
`RFC 4122`_ defines five versions of UUID. Each version has different generation
algorithms and properties. Which one you choose to use depends on your use-case.
You can find out more about their applications on the specific page for that
version.
-Version 1: Time-based
+Version 1: Gregorian Time
This version of UUID combines a timestamp, node value (in the form of a MAC
address from the local computer's network interface), and a clock sequence
to ensure uniqueness. For more details, see :doc:`rfc4122/version1`.
@@ -44,5 +45,10 @@ Version 5: Named-based (SHA-1)
deterministic UUID. The hashing algorithm used is SHA-1. For more details,
see :doc:`rfc4122/version5`.
+Version 6: Reordered Time
+ This version of UUID combines the features of a
+ :ref:`version 1 UUID ` with a *monotonically increasing*
+ UUID. For more details, see :ref:`rfc4122.version6`.
+
.. _RFC 4122: https://tools.ietf.org/html/rfc4122
diff --git a/docs/rfc4122/version1.rst b/docs/rfc4122/version1.rst
index e0bf719..8ac3147 100644
--- a/docs/rfc4122/version1.rst
+++ b/docs/rfc4122/version1.rst
@@ -1,8 +1,8 @@
.. _rfc4122.version1:
-=====================
-Version 1: Time-based
-=====================
+=========================
+Version 1: Gregorian Time
+=========================
A version 1 UUID uses the current time, along with the MAC address (or *node*)
for a network interface on the local machine. This serves two purposes:
@@ -27,7 +27,7 @@ is running on, using this value as the node. If it cannot find a MAC address, it
will generate a random node.
.. code-block:: php
- :caption: Generate a version 1, time-based UUID
+ :caption: Generate a version 1, Gregorian time UUID
:name: rfc4122.version1.example
use Ramsey\Uuid\Uuid;
@@ -59,7 +59,7 @@ sequence.
.. code-block:: php
:caption: Provide custom node and clock sequence to create a version 1,
- time-based UUID
+ Gregorian time UUID
:name: rfc4122.version1.custom-example
use Ramsey\Uuid\Provider\Node\StaticNodeProvider;
@@ -123,7 +123,7 @@ generate a random node value, and like the StaticNodeProvider, it also sets the
unicast/multicast bit for you.
.. code-block:: php
- :caption: Provide a random node value to create a version 1, time-based UUID
+ :caption: Provide a random node value to create a version 1, Gregorian time UUID
:name: rfc4122.version1.random-example
use Ramsey\Uuid\Provider\Node\RandomNodeProvider;
diff --git a/docs/rfc4122/version5.rst b/docs/rfc4122/version5.rst
index 86f8ba4..7af3158 100644
--- a/docs/rfc4122/version5.rst
+++ b/docs/rfc4122/version5.rst
@@ -83,8 +83,8 @@ The best way to do this is to generate a :ref:`version 1 ` or
printf("My namespace UUID is %s\n", $uuid->toString());
-This will generate a version 1, time-based UUID, which we'll store to a constant
-so we can reuse it as our own custom namespace.
+This will generate a version 1, Gregorian time UUID, which we'll store to a
+constant so we can reuse it as our own custom namespace.
.. code-block:: php
:caption: Use a custom namespace to create version 5, name-based UUIDs
diff --git a/docs/rfc4122/version6.rst b/docs/rfc4122/version6.rst
new file mode 100644
index 0000000..49e3ccf
--- /dev/null
+++ b/docs/rfc4122/version6.rst
@@ -0,0 +1,207 @@
+.. _rfc4122.version6:
+
+=========================
+Version 6: Reordered Time
+=========================
+
+.. note::
+
+ Version 6, reordered time UUIDs are a new format of UUID, proposed in an
+ `Internet-Draft under review`_ at the IETF. While the draft is still going
+ through the IETF process, the version 6 format is not expected to change
+ in any way that breaks compatibility.
+
+Version 6 UUIDs solve `two problems that have long existed`_ with the use of
+:ref:`version 1 ` UUIDs:
+
+1. Scattered database records
+2. Inability to sort by an identifier in a meaningful way (i.e., insert order)
+
+To overcome these issues, we need the ability to generate UUIDs that are
+*monotonically increasing* while still providing all the benefits of version
+1 UUIDs.
+
+Version 6 UUIDs do this by storing the time in standard byte order, instead of
+breaking it up and rearranging the time bytes, according to the `RFC 4122`_
+definition. All other fields remain the same, and the version maintains its
+position, according to RFC 4122.
+
+In all other ways, version 6 UUIDs function like version 1 UUIDs.
+
+.. tip::
+
+ Prior to version 4.0.0, ramsey/uuid provided a solution for this with the
+ :ref:`ordered-time codec `. Use of the
+ ordered-time codec is still valid and acceptable. However, you may replace
+ UUIDs generated using the ordered-time codec with version 6 UUIDs. Keep
+ reading to find out how.
+
+.. code-block:: php
+ :caption: Generate a version 6, reordered time UUID
+ :name: rfc4122.version6.example
+
+ use Ramsey\Uuid\Uuid;
+
+ $uuid = Uuid::uuid6();
+
+ printf(
+ "UUID: %s\nVersion: %d\nDate: %s\nNode: %s\n",
+ $uuid->toString(),
+ $uuid->getFields()->getVersion(),
+ $uuid->getDateTime()->format('r'),
+ $uuid->getFields()->getNode()->toString()
+ );
+
+This will generate a version 6 UUID and print out its string representation, the
+time the UUID was created, and the node used to create the UUID.
+
+It will look something like this:
+
+.. code-block:: text
+
+ UUID: 1ea60f56-b67b-61fc-829a-0242ac130003
+ Version: 6
+ Date: Sun, 08 Mar 2020 04:29:37 +0000
+ Node: 0242ac130003
+
+You may provide custom values for version 6 UUIDs, including node and clock
+sequence.
+
+.. code-block:: php
+ :caption: Provide custom node and clock sequence to create a version 6,
+ reordered time UUID
+ :name: rfc4122.version6.custom-example
+
+ use Ramsey\Uuid\Provider\Node\StaticNodeProvider;
+ use Ramsey\Uuid\Type\Hexadecimal;
+ use Ramsey\Uuid\Uuid;
+
+ $nodeProvider = new StaticNodeProvider(new Hexadecimal('121212121212'));
+ $clockSequence = 16383;
+
+ $uuid = Uuid::uuid6($nodeProvider->getNode(), $clockSequence);
+
+.. tip::
+
+ Version 6 UUIDs generated in ramsey/uuid are instances of UuidV6. Check out
+ the :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV6` API documentation to
+ learn more about what you can do with a UuidV6 instance.
+
+
+.. _rfc4122.version6.nodes:
+
+Custom and Random Nodes
+#######################
+
+In the :ref:`example above `, we provided a
+custom node when generating a version 6 UUID. You may also generate random
+node values.
+
+To learn more, see the :ref:`rfc4122.version1.custom` and
+:ref:`rfc4122.version1.random` sections under :ref:`rfc4122.version1`.
+
+
+.. _rfc4122.version6.clock:
+
+Clock Sequence
+##############
+
+In a version 6 UUID, the clock sequence serves the same purpose as in a version
+1 UUID. See :ref:`rfc4122.version1.clock` to learn more.
+
+
+.. _rfc4122.version6.version1-conversion:
+
+Version 1-to-6 Conversion
+#########################
+
+It is possible to convert back-and-forth between version 6 and version 1 UUIDs.
+
+.. code-block:: php
+ :caption: Convert a version 1 UUID to a version 6 UUID
+ :name: rfc4122.version6.convert-version1-example
+
+ use Ramsey\Uuid\Rfc4122\UuidV1;
+ use Ramsey\Uuid\Rfc4122\UuidV6;
+ use Ramsey\Uuid\Uuid;
+
+ $uuid1 = Uuid::fromString('3960c5d8-60f8-11ea-bc55-0242ac130003');
+
+ if ($uuid1 instanceof UuidV1) {
+ $uuid6 = UuidV6::fromUuidV1($uuid1);
+ }
+
+.. code-block:: php
+ :caption: Convert a version 6 UUID to a version 1 UUID
+ :name: rfc4122.version6.convert-version6-example
+
+ use Ramsey\Uuid\Rfc4122\UuidV6;
+ use Ramsey\Uuid\Uuid;
+
+ $uuid6 = Uuid::fromString('1ea60f83-960c-65d8-bc55-0242ac130003');
+
+ if ($uuid6 instanceof UuidV6) {
+ $uuid1 = $uuid6->toUuidV1();
+ }
+
+
+.. _rfc4122.version6.ordered-time-conversion:
+
+Ordered-time to Version 6 Conversion
+####################################
+
+You may convert UUIDs previously generated and stored using the
+:ref:`ordered-time codec ` into version 6 UUIDs.
+
+.. caution::
+
+ If you perform this conversion, the bytes and string representation of your
+ UUIDs will change. This will break any software that expects your
+ identifiers to be fixed.
+
+.. code-block:: php
+ :caption: Convert an ordered-time codec encoded UUID to a version 6 UUID
+ :name: rfc4122.version6.convert-ordered-time-example
+
+ use Ramsey\Uuid\Codec\OrderedTimeCodec;
+ use Ramsey\Uuid\Rfc4122\UuidV1;
+ use Ramsey\Uuid\Rfc4122\UuidV6;
+ use Ramsey\Uuid\UuidFactory;
+
+ // The bytes of a version 1 UUID previously stored in some datastore
+ // after encoding to bytes with the OrderedTimeCodec.
+ $bytes = hex2bin('11ea60faf17c8af6ad23acde48001122');
+
+ $factory = new UuidFactory();
+ $codec = new OrderedTimeCodec($factory->getUuidBuilder());
+
+ $factory->setCodec($codec);
+
+ $orderedTimeUuid = $factory->fromBytes($bytes);
+
+ if ($orderedTimeUuid instanceof UuidV1) {
+ $uuid6 = UuidV6::fromUuidV1($orderedTimeUuid);
+ }
+
+
+.. _rfc4122.version6.privacy:
+
+Privacy Concerns
+################
+
+Like :ref:`version 1 UUIDs `, version 6 UUIDs use a MAC
+address from a local hardware network interface. This means it is possible to
+uniquely identify the machine on which a version 6 UUID was created.
+
+If the value provided by the timestamp of a version 6 UUID is important to you,
+but you do not wish to expose the interface address of any of your local
+machines, see :ref:`rfc4122.version6.nodes`.
+
+If you do not need an identifier with a node value embedded in it, but you still
+need the benefit of a monotonically increasing unique identifier, see
+:ref:`customize.timestamp-first-comb-codec`.
+
+
+.. _Internet-Draft under review: https://datatracker.ietf.org/doc/draft-peabody-dispatch-new-uuid-format/
+.. _two problems that have long existed: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
+.. _RFC 4122: https://tools.ietf.org/html/rfc4122
From 078feed166b75827bce50c59e1094d9f6a86cab4 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 12 Sep 2022 20:56:42 -0500
Subject: [PATCH 35/74] chore: update nomenclature
---
src/Nonstandard/UuidV6.php | 6 +++---
src/Rfc4122/FieldsInterface.php | 3 ++-
src/Rfc4122/UuidV1.php | 4 ++--
src/Rfc4122/UuidV6.php | 2 +-
src/Uuid.php | 16 ++++------------
src/UuidFactoryInterface.php | 4 ++--
src/functions.php | 4 ++--
tests/Nonstandard/UuidV6Test.php | 2 +-
tests/Rfc4122/UuidV6Test.php | 2 +-
9 files changed, 18 insertions(+), 25 deletions(-)
diff --git a/src/Nonstandard/UuidV6.php b/src/Nonstandard/UuidV6.php
index 8ea22fd..62409e5 100644
--- a/src/Nonstandard/UuidV6.php
+++ b/src/Nonstandard/UuidV6.php
@@ -25,7 +25,7 @@ use Ramsey\Uuid\Rfc4122\UuidV6ConverterTrait;
use Ramsey\Uuid\Uuid;
/**
- * Reordered-time, or version 6, UUIDs include timestamp, clock sequence, and
+ * Reordered time, or version 6, UUIDs include timestamp, clock sequence, and
* node values that are combined into a 128-bit unsigned integer
*
* @deprecated Use {@see \Ramsey\Uuid\Rfc4122\UuidV6} instead.
@@ -41,7 +41,7 @@ class UuidV6 extends Uuid implements UuidInterface
use UuidV6ConverterTrait;
/**
- * Creates a version 6 (reordered-time) UUID
+ * Creates a version 6 (reordered time) UUID
*
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
@@ -60,7 +60,7 @@ class UuidV6 extends Uuid implements UuidInterface
if ($fields->getVersion() !== Uuid::UUID_TYPE_REORDERED_TIME) {
throw new InvalidArgumentException(
'Fields used to create a UuidV6 must represent a '
- . 'version 6 (ordered-time) UUID'
+ . 'version 6 (reordered time) UUID'
);
}
diff --git a/src/Rfc4122/FieldsInterface.php b/src/Rfc4122/FieldsInterface.php
index a303525..a0cc4f4 100644
--- a/src/Rfc4122/FieldsInterface.php
+++ b/src/Rfc4122/FieldsInterface.php
@@ -103,11 +103,12 @@ interface FieldsInterface extends BaseFieldsInterface
* The version number describes how the UUID was generated and has the
* following meaning:
*
- * 1. Time-based UUID
+ * 1. Gregorian time UUID
* 2. DCE security UUID
* 3. Name-based UUID hashed with MD5
* 4. Randomly generated UUID
* 5. Name-based UUID hashed with SHA-1
+ * 6. Reordered time UUID
*
* This returns `null` if the UUID is not an RFC 4122 variant, since version
* is only meaningful for this variant.
diff --git a/src/Rfc4122/UuidV1.php b/src/Rfc4122/UuidV1.php
index 8a9cad2..515c038 100644
--- a/src/Rfc4122/UuidV1.php
+++ b/src/Rfc4122/UuidV1.php
@@ -22,7 +22,7 @@ use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Uuid;
/**
- * Time-based, or version 1, UUIDs include timestamp, clock sequence, and node
+ * Gregorian time, or version 1, UUIDs include timestamp, clock sequence, and node
* values that are combined into a 128-bit unsigned integer
*
* @psalm-immutable
@@ -32,7 +32,7 @@ final class UuidV1 extends Uuid implements UuidInterface
use TimeTrait;
/**
- * Creates a version 1 (time-based) UUID
+ * Creates a version 1 (Gregorian time) UUID
*
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
diff --git a/src/Rfc4122/UuidV6.php b/src/Rfc4122/UuidV6.php
index 8b8c4b7..9b2ddee 100644
--- a/src/Rfc4122/UuidV6.php
+++ b/src/Rfc4122/UuidV6.php
@@ -17,7 +17,7 @@ namespace Ramsey\Uuid\Rfc4122;
use Ramsey\Uuid\Nonstandard\UuidV6 as NonstandardUuidV6;
/**
- * Reordered-time, or version 6, UUIDs include timestamp, clock sequence, and
+ * Reordered time, or version 6, UUIDs include timestamp, clock sequence, and
* node values that are combined into a 128-bit unsigned integer
*
* @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6
diff --git a/src/Uuid.php b/src/Uuid.php
index 3a7c8ec..deaa58e 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -116,7 +116,7 @@ class Uuid implements UuidInterface
public const VALID_PATTERN = '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$';
/**
- * Version 1 (time-based) UUID
+ * Version 1 (Gregorian time) UUID
*
* @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
*/
@@ -156,20 +156,12 @@ class Uuid implements UuidInterface
public const UUID_TYPE_HASH_SHA1 = 5;
/**
- * Version 6 (reordered-time) UUID
- *
- * This is named `UUID_TYPE_PEABODY`, since the specification is still in
- * draft form, and the primary author/editor's name is Brad Peabody.
- *
* @deprecated Use {@see Uuid::UUID_TYPE_REORDERED_TIME} instead.
- *
- * @link https://github.com/uuid6/uuid6-ietf-draft UUID version 6 IETF draft
- * @link http://gh.peabody.io/uuidv6/ "Version 6" UUIDs
*/
public const UUID_TYPE_PEABODY = 6;
/**
- * Version 6 (reordered-time) UUID
+ * Version 6 (reordered time) UUID
*
* @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6
*/
@@ -555,7 +547,7 @@ class Uuid implements UuidInterface
}
/**
- * Returns a version 1 (time-based) UUID from a host ID, sequence number,
+ * Returns a version 1 (Gregorian time) UUID from a host ID, sequence number,
* and the current time
*
* @param Hexadecimal|int|string|null $node A 48-bit number representing the
@@ -660,7 +652,7 @@ class Uuid implements UuidInterface
}
/**
- * Returns a version 6 (ordered-time) UUID from a host ID, sequence number,
+ * Returns a version 6 (reordered time) UUID from a host ID, sequence number,
* and the current time
*
* @param Hexadecimal|null $node A 48-bit number representing the hardware
diff --git a/src/UuidFactoryInterface.php b/src/UuidFactoryInterface.php
index bc0e615..d99fc9d 100644
--- a/src/UuidFactoryInterface.php
+++ b/src/UuidFactoryInterface.php
@@ -88,7 +88,7 @@ interface UuidFactoryInterface
public function getValidator(): ValidatorInterface;
/**
- * Returns a version 1 (time-based) UUID from a host ID, sequence number,
+ * Returns a version 1 (Gregorian time) UUID from a host ID, sequence number,
* and the current time
*
* @param Hexadecimal|int|string|null $node A 48-bit number representing the
@@ -166,7 +166,7 @@ interface UuidFactoryInterface
public function uuid5($ns, string $name): UuidInterface;
/**
- * Returns a version 6 (ordered-time) UUID from a host ID, sequence number,
+ * Returns a version 6 (reordered time) UUID from a host ID, sequence number,
* and the current time
*
* @param Hexadecimal|null $node A 48-bit number representing the hardware
diff --git a/src/functions.php b/src/functions.php
index d722f06..c3d3b49 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -19,7 +19,7 @@ use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
/**
- * Returns a version 1 (time-based) UUID from a host ID, sequence number,
+ * Returns a version 1 (Gregorian time) UUID from a host ID, sequence number,
* and the current time
*
* @param Hexadecimal|int|string|null $node A 48-bit number representing the
@@ -106,7 +106,7 @@ function v5($ns, string $name): string
}
/**
- * Returns a version 6 (ordered-time) UUID from a host ID, sequence number,
+ * Returns a version 6 (reordered time) UUID from a host ID, sequence number,
* and the current time
*
* @param Hexadecimal|null $node A 48-bit number representing the hardware
diff --git a/tests/Nonstandard/UuidV6Test.php b/tests/Nonstandard/UuidV6Test.php
index 0df8103..e5c71b4 100644
--- a/tests/Nonstandard/UuidV6Test.php
+++ b/tests/Nonstandard/UuidV6Test.php
@@ -37,7 +37,7 @@ class UuidV6Test extends TestCase
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(
'Fields used to create a UuidV6 must represent a '
- . 'version 6 (ordered-time) UUID'
+ . 'version 6 (reordered time) UUID'
);
new UuidV6($fields, $numberConverter, $codec, $timeConverter);
diff --git a/tests/Rfc4122/UuidV6Test.php b/tests/Rfc4122/UuidV6Test.php
index 1c72528..e9f74d6 100644
--- a/tests/Rfc4122/UuidV6Test.php
+++ b/tests/Rfc4122/UuidV6Test.php
@@ -37,7 +37,7 @@ class UuidV6Test extends TestCase
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(
'Fields used to create a UuidV6 must represent a '
- . 'version 6 (ordered-time) UUID'
+ . 'version 6 (reordered time) UUID'
);
new UuidV6($fields, $numberConverter, $codec, $timeConverter);
From e153b3420a3d569ad68af7da7f67e26600bfd8c1 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Tue, 13 Sep 2022 16:39:59 -0500
Subject: [PATCH 36/74] refactor: discard unnecessary trait
---
src/Nonstandard/UuidV6.php | 40 +++++++++++++++++-
src/Rfc4122/UuidV6ConverterTrait.php | 62 ----------------------------
2 files changed, 38 insertions(+), 64 deletions(-)
delete mode 100644 src/Rfc4122/UuidV6ConverterTrait.php
diff --git a/src/Nonstandard/UuidV6.php b/src/Nonstandard/UuidV6.php
index 62409e5..1a7bbaf 100644
--- a/src/Nonstandard/UuidV6.php
+++ b/src/Nonstandard/UuidV6.php
@@ -18,10 +18,11 @@ use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\InvalidArgumentException;
+use Ramsey\Uuid\Lazy\LazyUuidFromString;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Rfc4122\TimeTrait;
use Ramsey\Uuid\Rfc4122\UuidInterface;
-use Ramsey\Uuid\Rfc4122\UuidV6ConverterTrait;
+use Ramsey\Uuid\Rfc4122\UuidV1;
use Ramsey\Uuid\Uuid;
/**
@@ -38,7 +39,6 @@ use Ramsey\Uuid\Uuid;
class UuidV6 extends Uuid implements UuidInterface
{
use TimeTrait;
- use UuidV6ConverterTrait;
/**
* Creates a version 6 (reordered time) UUID
@@ -66,4 +66,40 @@ class UuidV6 extends Uuid implements UuidInterface
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
+
+ /**
+ * Converts this UUID into an instance of a version 1 UUID
+ */
+ public function toUuidV1(): UuidV1
+ {
+ $hex = $this->getHex()->toString();
+ $hex = substr($hex, 7, 5)
+ . substr($hex, 13, 3)
+ . substr($hex, 3, 4)
+ . '1' . substr($hex, 0, 3)
+ . substr($hex, 16);
+
+ /** @var LazyUuidFromString $uuid */
+ $uuid = Uuid::fromBytes((string) hex2bin($hex));
+
+ return $uuid->toUuidV1();
+ }
+
+ /**
+ * Converts a version 1 UUID into an instance of a version 6 UUID
+ */
+ public static function fromUuidV1(UuidV1 $uuidV1): \Ramsey\Uuid\Rfc4122\UuidV6
+ {
+ $hex = $uuidV1->getHex()->toString();
+ $hex = substr($hex, 13, 3)
+ . substr($hex, 8, 4)
+ . substr($hex, 0, 5)
+ . '6' . substr($hex, 5, 3)
+ . substr($hex, 16);
+
+ /** @var LazyUuidFromString $uuid */
+ $uuid = Uuid::fromBytes((string) hex2bin($hex));
+
+ return $uuid->toUuidV6();
+ }
}
diff --git a/src/Rfc4122/UuidV6ConverterTrait.php b/src/Rfc4122/UuidV6ConverterTrait.php
deleted file mode 100644
index cca0cff..0000000
--- a/src/Rfc4122/UuidV6ConverterTrait.php
+++ /dev/null
@@ -1,62 +0,0 @@
-
- * @license http://opensource.org/licenses/MIT MIT
- */
-
-declare(strict_types=1);
-
-namespace Ramsey\Uuid\Rfc4122;
-
-use Ramsey\Uuid\Lazy\LazyUuidFromString;
-use Ramsey\Uuid\Uuid;
-
-/**
- * Provides functionality to convert between UuidV1 and UuidV6
- *
- * @psalm-immutable
- */
-trait UuidV6ConverterTrait
-{
- /**
- * Converts this UUID into an instance of a version 1 UUID
- */
- public function toUuidV1(): UuidV1
- {
- $hex = $this->getHex()->toString();
- $hex = substr($hex, 7, 5)
- . substr($hex, 13, 3)
- . substr($hex, 3, 4)
- . '1' . substr($hex, 0, 3)
- . substr($hex, 16);
-
- /** @var LazyUuidFromString $uuid */
- $uuid = Uuid::fromBytes((string) hex2bin($hex));
-
- return $uuid->toUuidV1();
- }
-
- /**
- * Converts a version 1 UUID into an instance of a version 6 UUID
- */
- public static function fromUuidV1(UuidV1 $uuidV1): UuidV6
- {
- $hex = $uuidV1->getHex()->toString();
- $hex = substr($hex, 13, 3)
- . substr($hex, 8, 4)
- . substr($hex, 0, 5)
- . '6' . substr($hex, 5, 3)
- . substr($hex, 16);
-
- /** @var LazyUuidFromString $uuid */
- $uuid = Uuid::fromBytes((string) hex2bin($hex));
-
- return $uuid->toUuidV6();
- }
-}
From aa1e488afaa3cc5f62108b6fce66ef0b74eab0d5 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Tue, 13 Sep 2022 22:13:33 -0500
Subject: [PATCH 37/74] feat: support version 7 (Unix Epoch time) UUIDs
---
psalm-baseline.xml | 9 +-
src/Converter/Time/UnixTimeConverter.php | 93 ++++++++
src/FeatureSet.php | 32 ++-
src/Generator/UnixTimeGenerator.php | 59 ++++++
src/Rfc4122/Fields.php | 13 +-
src/Rfc4122/UuidBuilder.php | 39 ++--
src/Rfc4122/UuidV7.php | 60 ++++++
src/Rfc4122/VersionTrait.php | 15 +-
src/Uuid.php | 29 +++
src/UuidFactory.php | 28 ++-
.../Converter/Time/UnixTimeConverterTest.php | 198 ++++++++++++++++++
tests/FeatureSetTest.php | 8 +
tests/Generator/UnixTimeGeneratorTest.php | 39 ++++
tests/Guid/FieldsTest.php | 8 +-
tests/Rfc4122/FieldsTest.php | 20 +-
tests/Rfc4122/UuidBuilderTest.php | 7 +
tests/Rfc4122/UuidV7Test.php | 132 ++++++++++++
tests/UuidFactoryTest.php | 2 +
tests/UuidTest.php | 30 +++
tests/benchmark/UuidGenerationBench.php | 5 +
20 files changed, 784 insertions(+), 42 deletions(-)
create mode 100644 src/Converter/Time/UnixTimeConverter.php
create mode 100644 src/Generator/UnixTimeGenerator.php
create mode 100644 src/Rfc4122/UuidV7.php
create mode 100644 tests/Converter/Time/UnixTimeConverterTest.php
create mode 100644 tests/Generator/UnixTimeGeneratorTest.php
create mode 100644 tests/Rfc4122/UuidV7Test.php
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index cf70c9a..96f8617 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -95,13 +95,10 @@
$macs[]
-
-
- Uuid::UUID_TYPE_PEABODY
-
-
-
+
+ $this
+ $this
$this
$this
$this
diff --git a/src/Converter/Time/UnixTimeConverter.php b/src/Converter/Time/UnixTimeConverter.php
new file mode 100644
index 0000000..d94233f
--- /dev/null
+++ b/src/Converter/Time/UnixTimeConverter.php
@@ -0,0 +1,93 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Converter\Time;
+
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Math\CalculatorInterface;
+use Ramsey\Uuid\Math\RoundingMode;
+use Ramsey\Uuid\Type\Hexadecimal;
+use Ramsey\Uuid\Type\Integer as IntegerObject;
+use Ramsey\Uuid\Type\Time;
+
+use function explode;
+use function str_pad;
+
+use const STR_PAD_LEFT;
+
+/**
+ * UnixTimeConverter converts Unix Epoch timestamps to/from hexadecimal values
+ * consisting of milliseconds elapsed since the Unix Epoch
+ *
+ * @psalm-immutable
+ */
+class UnixTimeConverter implements TimeConverterInterface
+{
+ private const MILLISECONDS = 1000;
+
+ private CalculatorInterface $calculator;
+
+ public function __construct(CalculatorInterface $calculator)
+ {
+ $this->calculator = $calculator;
+ }
+
+ public function calculateTime(string $seconds, string $microseconds): Hexadecimal
+ {
+ $timestamp = new Time($seconds, $microseconds);
+
+ // Convert the seconds into milliseconds.
+ $sec = $this->calculator->multiply(
+ $timestamp->getSeconds(),
+ new IntegerObject(self::MILLISECONDS),
+ );
+
+ // Convert the microseconds into milliseconds; the scale is zero because
+ // we need to discard the fractional part.
+ $usec = $this->calculator->divide(
+ RoundingMode::DOWN, // Always round down to stay in the previous millisecond.
+ 0,
+ $timestamp->getMicroseconds(),
+ new IntegerObject(self::MILLISECONDS),
+ );
+
+ /** @var IntegerObject $unixTime */
+ $unixTime = $this->calculator->add($sec, $usec);
+
+ $unixTimeHex = str_pad(
+ $this->calculator->toHexadecimal($unixTime)->toString(),
+ 12,
+ '0',
+ STR_PAD_LEFT
+ );
+
+ return new Hexadecimal($unixTimeHex);
+ }
+
+ public function convertTime(Hexadecimal $uuidTimestamp): Time
+ {
+ $milliseconds = $this->calculator->toInteger($uuidTimestamp);
+
+ $unixTimestamp = $this->calculator->divide(
+ RoundingMode::HALF_UP,
+ 6,
+ $milliseconds,
+ new IntegerObject(self::MILLISECONDS)
+ );
+
+ $split = explode('.', (string) $unixTimestamp, 2);
+
+ return new Time($split[0], $split[1] ?? '0');
+ }
+}
diff --git a/src/FeatureSet.php b/src/FeatureSet.php
index 819f99a..482a8de 100644
--- a/src/FeatureSet.php
+++ b/src/FeatureSet.php
@@ -23,6 +23,7 @@ use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
+use Ramsey\Uuid\Converter\Time\UnixTimeConverter;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Generator\DceSecurityGenerator;
use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface;
@@ -35,6 +36,7 @@ use Ramsey\Uuid\Generator\RandomGeneratorFactory;
use Ramsey\Uuid\Generator\RandomGeneratorInterface;
use Ramsey\Uuid\Generator\TimeGeneratorFactory;
use Ramsey\Uuid\Generator\TimeGeneratorInterface;
+use Ramsey\Uuid\Generator\UnixTimeGenerator;
use Ramsey\Uuid\Guid\GuidBuilder;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Math\CalculatorInterface;
@@ -141,6 +143,8 @@ class FeatureSet
*/
private $calculator;
+ private TimeGeneratorInterface $unixTimeGenerator;
+
/**
* @param bool $useGuids True build UUIDs using the GuidStringCodec
* @param bool $force32Bit True to force the use of 32-bit functionality
@@ -164,15 +168,18 @@ class FeatureSet
$this->ignoreSystemNode = $ignoreSystemNode;
$this->enablePecl = $enablePecl;
+ $this->randomGenerator = $this->buildRandomGenerator();
$this->setCalculator(new BrickMathCalculator());
$this->builder = $this->buildUuidBuilder($useGuids);
$this->codec = $this->buildCodec($useGuids);
$this->nodeProvider = $this->buildNodeProvider();
$this->nameGenerator = $this->buildNameGenerator();
- $this->randomGenerator = $this->buildRandomGenerator();
$this->setTimeProvider(new SystemTimeProvider());
$this->setDceSecurityProvider(new SystemDceSecurityProvider());
$this->validator = new GenericValidator();
+
+ assert($this->timeProvider !== null);
+ $this->unixTimeGenerator = $this->buildUnixTimeGenerator($this->timeProvider);
}
/**
@@ -255,6 +262,14 @@ class FeatureSet
return $this->timeGenerator;
}
+ /**
+ * Returns the Unix Epoch time generator configured for this environment
+ */
+ public function getUnixTimeGenerator(): TimeGeneratorInterface
+ {
+ return $this->unixTimeGenerator;
+ }
+
/**
* Returns the validator configured for this environment
*/
@@ -396,6 +411,21 @@ class FeatureSet
))->getGenerator();
}
+ /**
+ * Returns a Unix Epoch time generator configured for this environment
+ *
+ * @param TimeProviderInterface $timeProvider The time provider to use with
+ * the time generator
+ */
+ private function buildUnixTimeGenerator(TimeProviderInterface $timeProvider): TimeGeneratorInterface
+ {
+ return new UnixTimeGenerator(
+ new UnixTimeConverter(new BrickMathCalculator()),
+ $timeProvider,
+ $this->randomGenerator,
+ );
+ }
+
/**
* Returns a name generator configured for this environment
*/
diff --git a/src/Generator/UnixTimeGenerator.php b/src/Generator/UnixTimeGenerator.php
new file mode 100644
index 0000000..74914dd
--- /dev/null
+++ b/src/Generator/UnixTimeGenerator.php
@@ -0,0 +1,59 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Generator;
+
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Provider\TimeProviderInterface;
+
+use function hex2bin;
+
+/**
+ * UnixTimeGenerator generates bytes that combine a 48-bit timestamp in
+ * milliseconds since the Unix Epoch with 80 random bits
+ */
+class UnixTimeGenerator implements TimeGeneratorInterface
+{
+ private RandomGeneratorInterface $randomGenerator;
+ private TimeConverterInterface $timeConverter;
+ private TimeProviderInterface $timeProvider;
+
+ public function __construct(
+ TimeConverterInterface $timeConverter,
+ TimeProviderInterface $timeProvider,
+ RandomGeneratorInterface $randomGenerator
+ ) {
+ $this->timeConverter = $timeConverter;
+ $this->timeProvider = $timeProvider;
+ $this->randomGenerator = $randomGenerator;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function generate($node = null, ?int $clockSeq = null): string
+ {
+ // Generate 10 random bytes to append to the string returned, since our
+ // time bytes will consist of 6 bytes.
+ $random = $this->randomGenerator->generate(10);
+
+ $time = $this->timeProvider->getTime();
+ $unixTimeHex = $this->timeConverter->calculateTime(
+ $time->getSeconds()->toString(),
+ $time->getMicroseconds()->toString(),
+ );
+
+ return hex2bin($unixTimeHex->toString()) . $random;
+ }
+}
diff --git a/src/Rfc4122/Fields.php b/src/Rfc4122/Fields.php
index 2ccc20b..6103cdc 100644
--- a/src/Rfc4122/Fields.php
+++ b/src/Rfc4122/Fields.php
@@ -150,7 +150,7 @@ final class Fields implements FieldsInterface
);
break;
- case Uuid::UUID_TYPE_PEABODY:
+ case Uuid::UUID_TYPE_REORDERED_TIME:
$timestamp = sprintf(
'%08s%04s%03x',
$this->getTimeLow()->toString(),
@@ -158,6 +158,17 @@ final class Fields implements FieldsInterface
hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff
);
+ break;
+ case Uuid::UUID_TYPE_UNIX_TIME:
+ // The Unix timestamp in version 7 UUIDs is a 48-bit number,
+ // but for consistency, we will return a 60-bit number, padded
+ // to the left with zeros.
+ $timestamp = sprintf(
+ '%011s%04s',
+ $this->getTimeLow()->toString(),
+ $this->getTimeMid()->toString(),
+ );
+
break;
default:
$timestamp = sprintf(
diff --git a/src/Rfc4122/UuidBuilder.php b/src/Rfc4122/UuidBuilder.php
index df7ab30..10eded9 100644
--- a/src/Rfc4122/UuidBuilder.php
+++ b/src/Rfc4122/UuidBuilder.php
@@ -17,10 +17,13 @@ namespace Ramsey\Uuid\Rfc4122;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Converter\Time\UnixTimeConverter;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
+use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Rfc4122\UuidInterface as Rfc4122UuidInterface;
+use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Throwable;
@@ -31,15 +34,9 @@ use Throwable;
*/
class UuidBuilder implements UuidBuilderInterface
{
- /**
- * @var NumberConverterInterface
- */
- private $numberConverter;
-
- /**
- * @var TimeConverterInterface
- */
- private $timeConverter;
+ private NumberConverterInterface $numberConverter;
+ private TimeConverterInterface $timeConverter;
+ private TimeConverterInterface $unixTimeConverter;
/**
* Constructs the DefaultUuidBuilder
@@ -47,14 +44,20 @@ class UuidBuilder implements UuidBuilderInterface
* @param NumberConverterInterface $numberConverter The number converter to
* use when constructing the Uuid
* @param TimeConverterInterface $timeConverter The time converter to use
- * for converting timestamps extracted from a UUID to Unix timestamps
+ * for converting Gregorian time extracted from version 1, 2, and 6
+ * UUIDs to Unix timestamps
+ * @param TimeConverterInterface|null $unixTimeConverter The time converter
+ * to use for converter Unix Epoch time extracted from version 7 UUIDs
+ * to Unix timestamps
*/
public function __construct(
NumberConverterInterface $numberConverter,
- TimeConverterInterface $timeConverter
+ TimeConverterInterface $timeConverter,
+ ?TimeConverterInterface $unixTimeConverter = null
) {
$this->numberConverter = $numberConverter;
$this->timeConverter = $timeConverter;
+ $this->unixTimeConverter = $unixTimeConverter ?? new UnixTimeConverter(new BrickMathCalculator());
}
/**
@@ -77,18 +80,20 @@ class UuidBuilder implements UuidBuilderInterface
}
switch ($fields->getVersion()) {
- case 1:
+ case Uuid::UUID_TYPE_TIME:
return new UuidV1($fields, $this->numberConverter, $codec, $this->timeConverter);
- case 2:
+ case Uuid::UUID_TYPE_DCE_SECURITY:
return new UuidV2($fields, $this->numberConverter, $codec, $this->timeConverter);
- case 3:
+ case Uuid::UUID_TYPE_HASH_MD5:
return new UuidV3($fields, $this->numberConverter, $codec, $this->timeConverter);
- case 4:
+ case Uuid::UUID_TYPE_RANDOM:
return new UuidV4($fields, $this->numberConverter, $codec, $this->timeConverter);
- case 5:
+ case Uuid::UUID_TYPE_HASH_SHA1:
return new UuidV5($fields, $this->numberConverter, $codec, $this->timeConverter);
- case 6:
+ case Uuid::UUID_TYPE_REORDERED_TIME:
return new UuidV6($fields, $this->numberConverter, $codec, $this->timeConverter);
+ case Uuid::UUID_TYPE_UNIX_TIME:
+ return new UuidV7($fields, $this->numberConverter, $codec, $this->unixTimeConverter);
}
throw new UnsupportedOperationException(
diff --git a/src/Rfc4122/UuidV7.php b/src/Rfc4122/UuidV7.php
new file mode 100644
index 0000000..90c2471
--- /dev/null
+++ b/src/Rfc4122/UuidV7.php
@@ -0,0 +1,60 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Rfc4122;
+
+use Ramsey\Uuid\Codec\CodecInterface;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Exception\InvalidArgumentException;
+use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
+use Ramsey\Uuid\Uuid;
+
+/**
+ * Gregorian time, or version 1, UUIDs include timestamp, clock sequence, and node
+ * values that are combined into a 128-bit unsigned integer
+ *
+ * @psalm-immutable
+ */
+final class UuidV7 extends Uuid implements UuidInterface
+{
+ use TimeTrait;
+
+ /**
+ * Creates a version 7 (Unix Epoch time) UUID
+ *
+ * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
+ * @param NumberConverterInterface $numberConverter The number converter to use
+ * for converting hex values to/from integers
+ * @param CodecInterface $codec The codec to use when encoding or decoding
+ * UUID strings
+ * @param TimeConverterInterface $timeConverter The time converter to use
+ * for converting timestamps extracted from a UUID to unix timestamps
+ */
+ public function __construct(
+ Rfc4122FieldsInterface $fields,
+ NumberConverterInterface $numberConverter,
+ CodecInterface $codec,
+ TimeConverterInterface $timeConverter
+ ) {
+ if ($fields->getVersion() !== Uuid::UUID_TYPE_UNIX_TIME) {
+ throw new InvalidArgumentException(
+ 'Fields used to create a UuidV7 must represent a '
+ . 'version 7 (Unix Epoch time) UUID'
+ );
+ }
+
+ parent::__construct($fields, $numberConverter, $codec, $timeConverter);
+ }
+}
diff --git a/src/Rfc4122/VersionTrait.php b/src/Rfc4122/VersionTrait.php
index cee55fb..b65ca7b 100644
--- a/src/Rfc4122/VersionTrait.php
+++ b/src/Rfc4122/VersionTrait.php
@@ -14,6 +14,8 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Rfc4122;
+use Ramsey\Uuid\Uuid;
+
/**
* Provides common functionality for handling the version, as defined by RFC 4122
*
@@ -43,12 +45,13 @@ trait VersionTrait
}
switch ($this->getVersion()) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
+ case Uuid::UUID_TYPE_TIME:
+ case Uuid::UUID_TYPE_DCE_SECURITY:
+ case Uuid::UUID_TYPE_HASH_MD5:
+ case Uuid::UUID_TYPE_RANDOM:
+ case Uuid::UUID_TYPE_HASH_SHA1:
+ case Uuid::UUID_TYPE_REORDERED_TIME:
+ case Uuid::UUID_TYPE_UNIX_TIME:
return true;
}
diff --git a/src/Uuid.php b/src/Uuid.php
index deaa58e..ee04da8 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -18,6 +18,7 @@ use DateTimeInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Exception\UnsupportedOperationException;
use Ramsey\Uuid\Fields\FieldsInterface;
use Ramsey\Uuid\Lazy\LazyUuidFromString;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
@@ -27,6 +28,7 @@ use ValueError;
use function assert;
use function bin2hex;
+use function method_exists;
use function preg_match;
use function sprintf;
use function str_replace;
@@ -167,6 +169,13 @@ class Uuid implements UuidInterface
*/
public const UUID_TYPE_REORDERED_TIME = 6;
+ /**
+ * Version 7 (Unix Epoch time) UUID
+ *
+ * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2 UUID Version 7
+ */
+ public const UUID_TYPE_UNIX_TIME = 7;
+
/**
* DCE Security principal domain
*
@@ -670,4 +679,24 @@ class Uuid implements UuidInterface
): UuidInterface {
return self::getFactory()->uuid6($node, $clockSeq);
}
+
+ /**
+ * Returns a version 7 (Unix Epoch time) UUID
+ *
+ * @return UuidInterface A UuidInterface instance that represents a
+ * version 7 UUID
+ */
+ public static function uuid7(): UuidInterface
+ {
+ $factory = self::getFactory();
+
+ if (method_exists($factory, 'uuid7')) {
+ /** @var UuidInterface */
+ return $factory->uuid7();
+ }
+
+ throw new UnsupportedOperationException(
+ 'The provided factory does not support the uuid7() method',
+ );
+ }
}
diff --git a/src/UuidFactory.php b/src/UuidFactory.php
index 6f2cea0..de3707c 100644
--- a/src/UuidFactory.php
+++ b/src/UuidFactory.php
@@ -98,6 +98,8 @@ class UuidFactory implements UuidFactoryInterface
/** @var bool whether the feature set was provided from outside, or we can operate under "default" assumptions */
private $isDefaultFeatureSet;
+ private TimeGeneratorInterface $unixTimeGenerator;
+
/**
* @param FeatureSet $features A set of available features in the current environment
*/
@@ -117,6 +119,7 @@ class UuidFactory implements UuidFactoryInterface
$this->timeGenerator = $features->getTimeGenerator();
$this->uuidBuilder = $features->getBuilder();
$this->validator = $features->getValidator();
+ $this->unixTimeGenerator = $features->getUnixTimeGenerator();
}
/**
@@ -342,7 +345,7 @@ class UuidFactory implements UuidFactoryInterface
$bytes = $timeGenerator->generate($nodeHex, $clockSeq);
- return $this->uuidFromBytesAndVersion($bytes, 1);
+ return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME);
}
/**
@@ -352,7 +355,7 @@ class UuidFactory implements UuidFactoryInterface
{
$bytes = $this->timeGenerator->generate($node, $clockSeq);
- return $this->uuidFromBytesAndVersion($bytes, 1);
+ return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME);
}
public function uuid2(
@@ -368,7 +371,7 @@ class UuidFactory implements UuidFactoryInterface
$clockSeq
);
- return $this->uuidFromBytesAndVersion($bytes, 2);
+ return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_DCE_SECURITY);
}
/**
@@ -377,14 +380,14 @@ class UuidFactory implements UuidFactoryInterface
*/
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(): UuidInterface
{
$bytes = $this->randomGenerator->generate(16);
- return $this->uuidFromBytesAndVersion($bytes, 4);
+ return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_RANDOM);
}
/**
@@ -393,7 +396,7 @@ class UuidFactory implements UuidFactoryInterface
*/
public function uuid5($ns, string $name): UuidInterface
{
- return $this->uuidFromNsAndName($ns, $name, 5, 'sha1');
+ return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_SHA1, 'sha1');
}
public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface
@@ -412,7 +415,18 @@ class UuidFactory implements UuidFactoryInterface
$v6Bytes = hex2bin(substr($v6, 1, 12) . '0' . substr($v6, -3));
$v6Bytes .= substr($bytes, 8);
- return $this->uuidFromBytesAndVersion($v6Bytes, 6);
+ return $this->uuidFromBytesAndVersion($v6Bytes, Uuid::UUID_TYPE_REORDERED_TIME);
+ }
+
+ /**
+ * Returns a version 7 (Unix Epoch time) UUID
+ *
+ * @return UuidInterface A UuidInterface instance that represents a
+ * version 7 UUID
+ */
+ public function uuid7(): UuidInterface
+ {
+ return $this->uuidFromBytesAndVersion($this->unixTimeGenerator->generate(), Uuid::UUID_TYPE_UNIX_TIME);
}
/**
diff --git a/tests/Converter/Time/UnixTimeConverterTest.php b/tests/Converter/Time/UnixTimeConverterTest.php
new file mode 100644
index 0000000..3a22f8a
--- /dev/null
+++ b/tests/Converter/Time/UnixTimeConverterTest.php
@@ -0,0 +1,198 @@
+convertTime($uuidTimestamp);
+
+ $this->assertSame($unixTimestamp, $result->getSeconds()->toString());
+ $this->assertSame($microseconds, $result->getMicroseconds()->toString());
+ }
+
+ /**
+ * @return array
+ */
+ public function provideConvertTime(): array
+ {
+ return [
+ [
+ 'uuidTimestamp' => new Hexadecimal('017F22E279B0'),
+ 'unixTimestamp' => '1645557742',
+ 'microseconds' => '0',
+ ],
+ [
+ 'uuidTimestamp' => new Hexadecimal('01384fc480fb'),
+ 'unixTimestamp' => '1341368074',
+ 'microseconds' => '491000',
+ ],
+ [
+ 'uuidTimestamp' => new Hexadecimal('016f8ca10161'),
+ 'unixTimestamp' => '1578612359',
+ 'microseconds' => '521000',
+ ],
+ [
+ 'uuidTimestamp' => new Hexadecimal('5dbe85111a5f'),
+ 'unixTimestamp' => '103072857659',
+ 'microseconds' => '999000',
+ ],
+
+ // This is the last possible time supported by v7 UUIDs.
+ // 10889-08-02 05:31:50.655 +00:00
+ [
+ 'uuidTimestamp' => new Hexadecimal('ffffffffffff'),
+ 'unixTimestamp' => '281474976710',
+ 'microseconds' => '655000',
+ ],
+
+ // This is the earliest possible date supported by v7 UUIDs.
+ // It is the Unix Epoch (big surprise!).
+ // 1970-01-01 00:00:00.0 +00:00
+ [
+ 'uuidTimestamp' => new Hexadecimal('000000000000'),
+ 'unixTimestamp' => '0',
+ 'microseconds' => '0',
+ ],
+
+ [
+ 'uuidTimestamp' => new Hexadecimal('000000000001'),
+ 'unixTimestamp' => '0',
+ 'microseconds' => '1000',
+ ],
+ [
+ 'uuidTimestamp' => new Hexadecimal('00000000000f'),
+ 'unixTimestamp' => '0',
+ 'microseconds' => '15000',
+ ],
+ [
+ 'uuidTimestamp' => new Hexadecimal('000000000064'),
+ 'unixTimestamp' => '0',
+ 'microseconds' => '100000',
+ ],
+ [
+ 'uuidTimestamp' => new Hexadecimal('0000000003e7'),
+ 'unixTimestamp' => '0',
+ 'microseconds' => '999000',
+ ],
+ [
+ 'uuidTimestamp' => new Hexadecimal('0000000003e8'),
+ 'unixTimestamp' => '1',
+ 'microseconds' => '0',
+ ],
+ [
+ 'uuidTimestamp' => new Hexadecimal('0000000003e9'),
+ 'unixTimestamp' => '1',
+ 'microseconds' => '1000',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider provideCalculateTime
+ */
+ public function testCalculateTime(string $seconds, string $microseconds, string $expected): void
+ {
+ $calculator = new BrickMathCalculator();
+ $converter = new UnixTimeConverter($calculator);
+
+ $result = $converter->calculateTime($seconds, $microseconds);
+
+ $this->assertSame($expected, $result->toString());
+ }
+
+ /**
+ * @return array
+ */
+ public function provideCalculateTime(): array
+ {
+ return [
+ [
+ 'seconds' => '1645557742',
+ 'microseconds' => '0',
+ 'expected' => '017f22e279b0',
+ ],
+ [
+ 'seconds' => '1341368074',
+ 'microseconds' => '491000',
+ 'expected' => '01384fc480fb',
+ ],
+ [
+ 'seconds' => '1578612359',
+ 'microseconds' => '521023',
+ 'expected' => '016f8ca10161',
+ ],
+ [
+ 'seconds' => '103072857659',
+ 'microseconds' => '999499',
+ 'expected' => '5dbe85111a5f',
+ ],
+ [
+ 'seconds' => '103072857659',
+ 'microseconds' => '999999',
+ 'expected' => '5dbe85111a5f',
+ ],
+
+ // This is the earliest possible date supported by v7 UUIDs.
+ // It is the Unix Epoch (big surprise!): 1970-01-01 00:00:00.0 +00:00
+ [
+ 'seconds' => '0',
+ 'microseconds' => '0',
+ 'expected' => '000000000000',
+ ],
+
+ // This is the last possible time supported by v7 UUIDs:
+ // 10889-08-02 05:31:50.655 +00:00
+ [
+ 'seconds' => '281474976710',
+ 'microseconds' => '655000',
+ 'expected' => 'ffffffffffff',
+ ],
+
+ [
+ 'seconds' => '0',
+ 'microseconds' => '1000',
+ 'expected' => '000000000001',
+ ],
+ [
+ 'seconds' => '0',
+ 'microseconds' => '15000',
+ 'expected' => '00000000000f',
+ ],
+ [
+ 'seconds' => '0',
+ 'microseconds' => '100000',
+ 'expected' => '000000000064',
+ ],
+ [
+ 'seconds' => '0',
+ 'microseconds' => '999000',
+ 'expected' => '0000000003e7',
+ ],
+ [
+ 'seconds' => '1',
+ 'microseconds' => '0',
+ 'expected' => '0000000003e8',
+ ],
+ [
+ 'seconds' => '1',
+ 'microseconds' => '1000',
+ 'expected' => '0000000003e9',
+ ],
+ ];
+ }
+}
diff --git a/tests/FeatureSetTest.php b/tests/FeatureSetTest.php
index 407322d..62b8269 100644
--- a/tests/FeatureSetTest.php
+++ b/tests/FeatureSetTest.php
@@ -10,6 +10,7 @@ use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\FeatureSet;
use Ramsey\Uuid\Generator\DefaultNameGenerator;
use Ramsey\Uuid\Generator\PeclUuidTimeGenerator;
+use Ramsey\Uuid\Generator\UnixTimeGenerator;
use Ramsey\Uuid\Guid\GuidBuilder;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Provider\NodeProviderInterface;
@@ -77,4 +78,11 @@ class FeatureSetTest extends TestCase
$this->assertSame($nodeProvider, $featureSet->getNodeProvider());
}
+
+ public function testGetUnixTimeGenerator(): void
+ {
+ $featureSet = new FeatureSet();
+
+ $this->assertInstanceOf(UnixTimeGenerator::class, $featureSet->getUnixTimeGenerator());
+ }
}
diff --git a/tests/Generator/UnixTimeGeneratorTest.php b/tests/Generator/UnixTimeGeneratorTest.php
new file mode 100644
index 0000000..1b7a93d
--- /dev/null
+++ b/tests/Generator/UnixTimeGeneratorTest.php
@@ -0,0 +1,39 @@
+ new Time('1578612359', '521023'),
+ ]);
+
+ /** @var RandomGeneratorInterface&MockInterface $randomGenerator */
+ $randomGenerator = Mockery::mock(RandomGeneratorInterface::class);
+ $randomGenerator->expects()->generate(10)->andReturns("\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00");
+
+ $unixTimeGenerator = new UnixTimeGenerator($unixTimeConverter, $timeProvider, $randomGenerator);
+
+ $this->assertSame(
+ "\x01\x6f\x8c\xa1\x01\x61\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00",
+ $unixTimeGenerator->generate(),
+ );
+ }
+}
diff --git a/tests/Guid/FieldsTest.php b/tests/Guid/FieldsTest.php
index 5c363db..d0f0689 100644
--- a/tests/Guid/FieldsTest.php
+++ b/tests/Guid/FieldsTest.php
@@ -89,9 +89,13 @@ class FieldsTest extends TestCase
// representations, which are never in GUID byte order.
return [
['b08c6fff7dc5e1018b210800200c9a66'],
- ['b08c6fff7dc5e1719b210800200c9a66'],
- ['b08c6fff7dc5e181ab210800200c9a66'],
['b08c6fff7dc5e191bb210800200c9a66'],
+ ['b08c6fff7dc5e1a19b210800200c9a66'],
+ ['b08c6fff7dc5e1b1ab210800200c9a66'],
+ ['b08c6fff7dc5e1c1ab210800200c9a66'],
+ ['b08c6fff7dc5e1d1ab210800200c9a66'],
+ ['b08c6fff7dc5e1e1ab210800200c9a66'],
+ ['b08c6fff7dc5e1f1ab210800200c9a66'],
];
}
diff --git a/tests/Rfc4122/FieldsTest.php b/tests/Rfc4122/FieldsTest.php
index b34a3d3..97f7497 100644
--- a/tests/Rfc4122/FieldsTest.php
+++ b/tests/Rfc4122/FieldsTest.php
@@ -84,9 +84,13 @@ class FieldsTest extends TestCase
{
return [
['ff6f8cb0-c57d-01e1-8b21-0800200c9a66'],
- ['ff6f8cb0-c57d-71e1-9b21-0800200c9a66'],
- ['ff6f8cb0-c57d-81e1-ab21-0800200c9a66'],
['ff6f8cb0-c57d-91e1-bb21-0800200c9a66'],
+ ['ff6f8cb0-c57d-a1e1-9b21-0800200c9a66'],
+ ['ff6f8cb0-c57d-b1e1-ab21-0800200c9a66'],
+ ['ff6f8cb0-c57d-c1e1-ab21-0800200c9a66'],
+ ['ff6f8cb0-c57d-d1e1-ab21-0800200c9a66'],
+ ['ff6f8cb0-c57d-e1e1-ab21-0800200c9a66'],
+ ['ff6f8cb0-c57d-f1e1-ab21-0800200c9a66'],
];
}
@@ -198,6 +202,18 @@ class FieldsTest extends TestCase
['000001f5-5cde-21ea-8400-0242ac130003', 'getVariant', 2],
['000001f5-5cde-21ea-8400-0242ac130003', 'getVersion', 2],
['000001f5-5cde-21ea-8400-0242ac130003', 'isNil', false],
+
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getClockSeq', '1b21'],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getClockSeqHiAndReserved', '9b'],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getClockSeqLow', '21'],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getNode', '0800200c9a66'],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getTimeHiAndVersion', '71e1'],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getTimeLow', '018339f0'],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getTimeMid', '1b83'],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getTimestamp', '000018339f01b83'],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getVariant', 2],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'getVersion', 7],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'isNil', false],
];
}
diff --git a/tests/Rfc4122/UuidBuilderTest.php b/tests/Rfc4122/UuidBuilderTest.php
index e234fc3..bf8a816 100644
--- a/tests/Rfc4122/UuidBuilderTest.php
+++ b/tests/Rfc4122/UuidBuilderTest.php
@@ -20,6 +20,7 @@ use Ramsey\Uuid\Rfc4122\UuidV3;
use Ramsey\Uuid\Rfc4122\UuidV4;
use Ramsey\Uuid\Rfc4122\UuidV5;
use Ramsey\Uuid\Rfc4122\UuidV6;
+use Ramsey\Uuid\Rfc4122\UuidV7;
use Ramsey\Uuid\Test\TestCase;
use function hex2bin;
@@ -95,6 +96,12 @@ class UuidBuilderTest extends TestCase
'expectedClass' => NonstandardUuidV6::class,
'expectedVersion' => 6,
],
+
+ [
+ 'uuid' => 'ff6f8cb0-c57d-71e1-9b21-0800200c9a66',
+ 'expectedClass' => UuidV7::class,
+ 'expectedVersion' => 7,
+ ],
];
}
diff --git a/tests/Rfc4122/UuidV7Test.php b/tests/Rfc4122/UuidV7Test.php
new file mode 100644
index 0000000..fd3e5a4
--- /dev/null
+++ b/tests/Rfc4122/UuidV7Test.php
@@ -0,0 +1,132 @@
+ $version,
+ ]);
+
+ $numberConverter = Mockery::mock(NumberConverterInterface::class);
+ $codec = Mockery::mock(CodecInterface::class);
+ $timeConverter = Mockery::mock(TimeConverterInterface::class);
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage(
+ 'Fields used to create a UuidV7 must represent a '
+ . 'version 7 (Unix Epoch time) UUID'
+ );
+
+ new UuidV7($fields, $numberConverter, $codec, $timeConverter);
+ }
+
+ /**
+ * @return array
+ */
+ public function provideTestVersions(): array
+ {
+ return [
+ ['version' => 0],
+ ['version' => 1],
+ ['version' => 2],
+ ['version' => 3],
+ ['version' => 4],
+ ['version' => 5],
+ ['version' => 6],
+ ['version' => 8],
+ ['version' => 9],
+ ];
+ }
+
+ /**
+ * @param non-empty-string $uuid
+ *
+ * @dataProvider provideUuidV7WithMicroseconds
+ */
+ public function testGetDateTimeProperlyHandlesMicroseconds(string $uuid, string $expected): void
+ {
+ /** @var UuidV7 $object */
+ $object = Uuid::fromString($uuid);
+
+ $date = $object->getDateTime();
+
+ $this->assertInstanceOf(DateTimeImmutable::class, $date);
+ $this->assertSame($expected, $date->format('U.u'));
+ }
+
+ /**
+ * @return array
+ */
+ public function provideUuidV7WithMicroseconds(): array
+ {
+ return [
+ [
+ 'uuid' => '00000000-0001-71b2-9669-00007ffffffe',
+ 'expected' => '0.001000',
+ ],
+ [
+ 'uuid' => '00000000-000f-71b2-9669-00007ffffffe',
+ 'expected' => '0.015000',
+ ],
+ [
+ 'uuid' => '00000000-0064-71b2-9669-00007ffffffe',
+ 'expected' => '0.100000',
+ ],
+ [
+ 'uuid' => '00000000-03e7-71b2-9669-00007ffffffe',
+ 'expected' => '0.999000',
+ ],
+ [
+ 'uuid' => '00000000-03e8-71b2-9669-00007ffffffe',
+ 'expected' => '1.000000',
+ ],
+ [
+ 'uuid' => '00000000-03e9-71b2-9669-00007ffffffe',
+ 'expected' => '1.001000',
+ ],
+ ];
+ }
+
+ public function testGetDateTimeThrowsException(): void
+ {
+ $fields = Mockery::mock(FieldsInterface::class, [
+ 'getVersion' => 7,
+ 'getTimestamp' => new Hexadecimal('0'),
+ ]);
+
+ $numberConverter = Mockery::mock(NumberConverterInterface::class);
+ $codec = Mockery::mock(CodecInterface::class);
+
+ $timeConverter = Mockery::mock(TimeConverterInterface::class, [
+ 'convertTime' => new Time('0', '1234567'),
+ ]);
+
+ $uuid = new UuidV7($fields, $numberConverter, $codec, $timeConverter);
+
+ $this->expectException(DateTimeException::class);
+
+ $uuid->getDateTime();
+ }
+}
diff --git a/tests/UuidFactoryTest.php b/tests/UuidFactoryTest.php
index 0102b18..19ec914 100644
--- a/tests/UuidFactoryTest.php
+++ b/tests/UuidFactoryTest.php
@@ -67,6 +67,7 @@ class UuidFactoryTest extends TestCase
$randomGenerator = Mockery::mock(RandomGeneratorInterface::class);
$timeConverter = Mockery::mock(TimeConverterInterface::class);
$timeGenerator = Mockery::mock(TimeGeneratorInterface::class);
+ $unixTimeGenerator = Mockery::mock(TimeGeneratorInterface::class);
$nameGenerator = Mockery::mock(NameGeneratorInterface::class);
$dceSecurityGenerator = Mockery::mock(DceSecurityGeneratorInterface::class);
$numberConverter = Mockery::mock(NumberConverterInterface::class);
@@ -84,6 +85,7 @@ class UuidFactoryTest extends TestCase
'getNumberConverter' => $numberConverter,
'getBuilder' => $builder,
'getValidator' => $validator,
+ 'getUnixTimeGenerator' => $unixTimeGenerator,
]);
$uuidFactory = new UuidFactory($featureSet);
diff --git a/tests/UuidTest.php b/tests/UuidTest.php
index c2313b7..4be8c72 100644
--- a/tests/UuidTest.php
+++ b/tests/UuidTest.php
@@ -8,6 +8,7 @@ use Brick\Math\BigDecimal;
use Brick\Math\RoundingMode;
use DateTimeInterface;
use Mockery;
+use Mockery\MockInterface;
use PHPUnit\Framework\MockObject\MockObject;
use Ramsey\Uuid\Builder\DefaultUuidBuilder;
use Ramsey\Uuid\Codec\StringCodec;
@@ -33,6 +34,7 @@ use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Time;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidFactory;
+use Ramsey\Uuid\UuidFactoryInterface;
use Ramsey\Uuid\UuidInterface;
use Ramsey\Uuid\Validator\GenericValidator;
use Ramsey\Uuid\Validator\ValidatorInterface;
@@ -705,6 +707,27 @@ class UuidTest extends TestCase
$this->assertSame(6, $uuid->getVersion());
}
+ public function testUuid7(): void
+ {
+ $uuid = Uuid::uuid7();
+ $this->assertInstanceOf(DateTimeInterface::class, $uuid->getDateTime());
+ $this->assertSame(2, $uuid->getVariant());
+ $this->assertSame(7, $uuid->getVersion());
+ }
+
+ public function testUuid7ThrowsExceptionForUnsupportedFactory(): void
+ {
+ /** @var UuidFactoryInterface&MockInterface $factory */
+ $factory = Mockery::mock(UuidFactoryInterface::class);
+
+ Uuid::setFactory($factory);
+
+ $this->expectException(UnsupportedOperationException::class);
+ $this->expectExceptionMessage('The provided factory does not support the uuid7() method');
+
+ Uuid::uuid7();
+ }
+
/**
* Tests known version-3 UUIDs
*
@@ -1649,6 +1672,13 @@ class UuidTest extends TestCase
{
$uuid = Uuid::fromString('886313e1-3b8a-6372-9b90-0c9aee199e5d');
$this->assertSame($uuid->getVersion(), Uuid::UUID_TYPE_PEABODY);
+ $this->assertSame($uuid->getVersion(), Uuid::UUID_TYPE_REORDERED_TIME);
+ }
+
+ public function testUuidVersionConstantForVersion7(): void
+ {
+ $uuid = Uuid::fromString('886313e1-3b8a-7372-9b90-0c9aee199e5d');
+ $this->assertSame($uuid->getVersion(), Uuid::UUID_TYPE_UNIX_TIME);
}
public function testGetDateTimeThrowsExceptionWhenDateTimeCannotParseDate(): void
diff --git a/tests/benchmark/UuidGenerationBench.php b/tests/benchmark/UuidGenerationBench.php
index c547a9f..c3838e1 100644
--- a/tests/benchmark/UuidGenerationBench.php
+++ b/tests/benchmark/UuidGenerationBench.php
@@ -99,4 +99,9 @@ final class UuidGenerationBench
{
Uuid::uuid6($this->node, $this->clockSequence);
}
+
+ public function benchUuid7Generation(): void
+ {
+ Uuid::uuid7();
+ }
}
From 1d71a2d4a0e21577e8c6c65c30d9f2e34378a834 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Tue, 13 Sep 2022 22:14:11 -0500
Subject: [PATCH 38/74] chore: add composer-repl for local testing
---
composer.json | 4 +-
composer.lock | 927 +++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 928 insertions(+), 3 deletions(-)
diff --git a/composer.json b/composer.json
index 688bd4f..9653cad 100644
--- a/composer.json
+++ b/composer.json
@@ -32,6 +32,7 @@
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-phpunit": "^1.1",
"phpunit/phpunit": "^8.5 || ^9",
+ "ramsey/composer-repl": "^1.4",
"slevomat/coding-standard": "^8.4",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.9"
@@ -69,7 +70,8 @@
"captainhook/plugin-composer": true,
"ergebnis/composer-normalize": true,
"phpstan/extension-installer": true,
- "dealerdirect/phpcodesniffer-composer-installer": true
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "ramsey/composer-repl": true
},
"sort-packages": true
},
diff --git a/composer.lock b/composer.lock
index d78caa5..14ccad8 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "91397bc20b15f841226c143cfe428034",
+ "content-hash": "93dcc08db8ab52aea6a540b1fa09dcfd",
"packages": [
{
"name": "brick/math",
@@ -526,6 +526,336 @@
},
"time": "2022-01-28T04:35:22+00:00"
},
+ {
+ "name": "composer/ca-bundle",
+ "version": "1.3.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/ca-bundle.git",
+ "reference": "30897edbfb15e784fe55587b4f73ceefd3c4d98c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/ca-bundle/zipball/30897edbfb15e784fe55587b4f73ceefd3c4d98c",
+ "reference": "30897edbfb15e784fe55587b4f73ceefd3c4d98c",
+ "shasum": ""
+ },
+ "require": {
+ "ext-openssl": "*",
+ "ext-pcre": "*",
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^0.12.55",
+ "psr/log": "^1.0",
+ "symfony/phpunit-bridge": "^4.2 || ^5",
+ "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\CaBundle\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
+ "keywords": [
+ "cabundle",
+ "cacert",
+ "certificate",
+ "ssl",
+ "tls"
+ ],
+ "support": {
+ "irc": "irc://irc.freenode.org/composer",
+ "issues": "https://github.com/composer/ca-bundle/issues",
+ "source": "https://github.com/composer/ca-bundle/tree/1.3.3"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-07-20T07:14:26+00:00"
+ },
+ {
+ "name": "composer/class-map-generator",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/class-map-generator.git",
+ "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/class-map-generator/zipball/1e1cb2b791facb2dfe32932a7718cf2571187513",
+ "reference": "1e1cb2b791facb2dfe32932a7718cf2571187513",
+ "shasum": ""
+ },
+ "require": {
+ "composer/pcre": "^2 || ^3",
+ "php": "^7.2 || ^8.0",
+ "symfony/finder": "^4.4 || ^5.3 || ^6"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.6",
+ "phpstan/phpstan-deprecation-rules": "^1",
+ "phpstan/phpstan-phpunit": "^1",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "symfony/filesystem": "^5.4 || ^6",
+ "symfony/phpunit-bridge": "^5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\ClassMapGenerator\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "https://seld.be"
+ }
+ ],
+ "description": "Utilities to scan PHP code and generate class maps.",
+ "keywords": [
+ "classmap"
+ ],
+ "support": {
+ "issues": "https://github.com/composer/class-map-generator/issues",
+ "source": "https://github.com/composer/class-map-generator/tree/1.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-06-19T11:31:27+00:00"
+ },
+ {
+ "name": "composer/composer",
+ "version": "2.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/composer.git",
+ "reference": "777d542e3af65f8e7a66a4d98ce7a697da339414"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/composer/zipball/777d542e3af65f8e7a66a4d98ce7a697da339414",
+ "reference": "777d542e3af65f8e7a66a4d98ce7a697da339414",
+ "shasum": ""
+ },
+ "require": {
+ "composer/ca-bundle": "^1.0",
+ "composer/class-map-generator": "^1.0",
+ "composer/metadata-minifier": "^1.0",
+ "composer/pcre": "^2 || ^3",
+ "composer/semver": "^3.0",
+ "composer/spdx-licenses": "^1.5.7",
+ "composer/xdebug-handler": "^2.0.2 || ^3.0.3",
+ "justinrainbow/json-schema": "^5.2.11",
+ "php": "^7.2.5 || ^8.0",
+ "psr/log": "^1.0 || ^2.0 || ^3.0",
+ "react/promise": "^2.8",
+ "seld/jsonlint": "^1.4",
+ "seld/phar-utils": "^1.2",
+ "seld/signal-handler": "^2.0",
+ "symfony/console": "^5.4.11 || ^6.0.11",
+ "symfony/filesystem": "^5.4 || ^6.0",
+ "symfony/finder": "^5.4 || ^6.0",
+ "symfony/polyfill-php73": "^1.24",
+ "symfony/polyfill-php80": "^1.24",
+ "symfony/process": "^5.4 || ^6.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.4.1",
+ "phpstan/phpstan-deprecation-rules": "^1",
+ "phpstan/phpstan-phpunit": "^1.0",
+ "phpstan/phpstan-strict-rules": "^1",
+ "phpstan/phpstan-symfony": "^1.1",
+ "symfony/phpunit-bridge": "^6.0"
+ },
+ "suggest": {
+ "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages",
+ "ext-zip": "Enabling the zip extension allows you to unzip archives",
+ "ext-zlib": "Allow gzip compression of HTTP requests"
+ },
+ "bin": [
+ "bin/composer"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.4-dev"
+ },
+ "phpstan": {
+ "includes": [
+ "phpstan/rules.neon"
+ ]
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\": "src/Composer"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "https://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "https://seld.be"
+ }
+ ],
+ "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.",
+ "homepage": "https://getcomposer.org/",
+ "keywords": [
+ "autoload",
+ "dependency",
+ "package"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/composer/issues",
+ "source": "https://github.com/composer/composer/tree/2.4.1"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-08-20T09:44:50+00:00"
+ },
+ {
+ "name": "composer/metadata-minifier",
+ "version": "1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/metadata-minifier.git",
+ "reference": "c549d23829536f0d0e984aaabbf02af91f443207"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/metadata-minifier/zipball/c549d23829536f0d0e984aaabbf02af91f443207",
+ "reference": "c549d23829536f0d0e984aaabbf02af91f443207",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "composer/composer": "^2",
+ "phpstan/phpstan": "^0.12.55",
+ "symfony/phpunit-bridge": "^4.2 || ^5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\MetadataMinifier\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Small utility library that handles metadata minification and expansion.",
+ "keywords": [
+ "composer",
+ "compression"
+ ],
+ "support": {
+ "issues": "https://github.com/composer/metadata-minifier/issues",
+ "source": "https://github.com/composer/metadata-minifier/tree/1.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2021-04-07T13:37:33+00:00"
+ },
{
"name": "composer/package-versions-deprecated",
"version": "1.11.99.5",
@@ -751,6 +1081,86 @@
],
"time": "2022-04-01T19:23:25+00:00"
},
+ {
+ "name": "composer/spdx-licenses",
+ "version": "1.5.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/spdx-licenses.git",
+ "reference": "c848241796da2abf65837d51dce1fae55a960149"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/c848241796da2abf65837d51dce1fae55a960149",
+ "reference": "c848241796da2abf65837d51dce1fae55a960149",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.3.2 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^0.12.55",
+ "symfony/phpunit-bridge": "^4.2 || ^5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Spdx\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nils Adermann",
+ "email": "naderman@naderman.de",
+ "homepage": "http://www.naderman.de"
+ },
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ },
+ {
+ "name": "Rob Bast",
+ "email": "rob.bast@gmail.com",
+ "homepage": "http://robbast.nl"
+ }
+ ],
+ "description": "SPDX licenses list and validation library.",
+ "keywords": [
+ "license",
+ "spdx",
+ "validator"
+ ],
+ "support": {
+ "irc": "irc://irc.freenode.org/composer",
+ "issues": "https://github.com/composer/spdx-licenses/issues",
+ "source": "https://github.com/composer/spdx-licenses/tree/1.5.7"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-05-23T07:37:50+00:00"
+ },
{
"name": "composer/xdebug-handler",
"version": "3.0.3",
@@ -3766,6 +4176,322 @@
},
"time": "2021-07-14T16:41:46+00:00"
},
+ {
+ "name": "psy/psysh",
+ "version": "v0.11.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/bobthecow/psysh.git",
+ "reference": "f455acf3645262ae389b10e9beba0c358aa6994e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/bobthecow/psysh/zipball/f455acf3645262ae389b10e9beba0c358aa6994e",
+ "reference": "f455acf3645262ae389b10e9beba0c358aa6994e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "nikic/php-parser": "^4.0 || ^3.1",
+ "php": "^8.0 || ^7.0.8",
+ "symfony/console": "^6.0 || ^5.0 || ^4.0 || ^3.4",
+ "symfony/var-dumper": "^6.0 || ^5.0 || ^4.0 || ^3.4"
+ },
+ "conflict": {
+ "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.2"
+ },
+ "suggest": {
+ "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
+ "ext-pdo-sqlite": "The doc command requires SQLite to work.",
+ "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.",
+ "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history."
+ },
+ "bin": [
+ "bin/psysh"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "0.11.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "Psy\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Justin Hileman",
+ "email": "justin@justinhileman.info",
+ "homepage": "http://justinhileman.com"
+ }
+ ],
+ "description": "An interactive shell for modern PHP.",
+ "homepage": "http://psysh.org",
+ "keywords": [
+ "REPL",
+ "console",
+ "interactive",
+ "shell"
+ ],
+ "support": {
+ "issues": "https://github.com/bobthecow/psysh/issues",
+ "source": "https://github.com/bobthecow/psysh/tree/v0.11.8"
+ },
+ "time": "2022-07-28T14:25:11+00:00"
+ },
+ {
+ "name": "ramsey/composer-repl",
+ "version": "1.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ramsey/composer-repl.git",
+ "reference": "24553610c07df626c7dfd44ef328b7ae3349366f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ramsey/composer-repl/zipball/24553610c07df626c7dfd44ef328b7ae3349366f",
+ "reference": "24553610c07df626c7dfd44ef328b7ae3349366f",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^2",
+ "php": "^7.4 || ^8",
+ "ramsey/composer-repl-lib": "^1.1"
+ },
+ "require-dev": {
+ "captainhook/captainhook": "^5.10",
+ "captainhook/plugin-composer": "^5.3",
+ "ergebnis/composer-normalize": "^2.25",
+ "roave/security-advisories": "dev-latest"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.x-dev"
+ },
+ "captainhook": {
+ "force-install": true
+ },
+ "class": "Ramsey\\Dev\\Repl\\Composer\\ReplPlugin",
+ "ramsey/conventional-commits": {
+ "configFile": "conventional-commits.json"
+ },
+ "ramsey/devtools": {
+ "command-prefix": "dev"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ben Ramsey",
+ "email": "ben@benramsey.com",
+ "homepage": "https://benramsey.com"
+ }
+ ],
+ "description": "A REPL for PHP built into Composer.",
+ "keywords": [
+ "REPL",
+ "psysh",
+ "shell"
+ ],
+ "support": {
+ "issues": "https://github.com/ramsey/composer-repl/issues",
+ "source": "https://github.com/ramsey/composer-repl/tree/1.4.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/ramsey",
+ "type": "github"
+ }
+ ],
+ "time": "2022-04-17T02:07:54+00:00"
+ },
+ {
+ "name": "ramsey/composer-repl-lib",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ramsey/composer-repl-lib.git",
+ "reference": "53f7666f1f4b49711741ad22b633671a312a6fdc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ramsey/composer-repl-lib/zipball/53f7666f1f4b49711741ad22b633671a312a6fdc",
+ "reference": "53f7666f1f4b49711741ad22b633671a312a6fdc",
+ "shasum": ""
+ },
+ "require": {
+ "composer/composer": "^2.1.9",
+ "php": "^7.4 || ^8",
+ "phpunit/phpunit": "^6 || ^7 || ^8 || ^9",
+ "psy/psysh": "^0.11.0",
+ "symfony/console": "^4.4.30 || ^5.3.7 || ^6",
+ "symfony/process": "^4.4.30 || ^5.3.7 || ^6"
+ },
+ "require-dev": {
+ "captainhook/captainhook": "^5.10",
+ "captainhook/plugin-composer": "^5.3",
+ "ergebnis/composer-normalize": "^2.25",
+ "hamcrest/hamcrest-php": "^2.0",
+ "mockery/mockery": "^1.5",
+ "php-parallel-lint/php-console-highlighter": "^1.0",
+ "php-parallel-lint/php-parallel-lint": "^1.3",
+ "phpstan/extension-installer": "^1.1",
+ "phpstan/phpstan": "^1.5",
+ "phpstan/phpstan-mockery": "^1.0",
+ "phpstan/phpstan-phpunit": "^1.1",
+ "psalm/plugin-mockery": "^0.9.1",
+ "psalm/plugin-phpunit": "^0.16.1",
+ "ramsey/coding-standard": "^2.0.3",
+ "roave/security-advisories": "dev-latest",
+ "vimeo/psalm": "^4.22"
+ },
+ "bin": [
+ "bin/repl"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.x-dev"
+ },
+ "captainhook": {
+ "force-install": true
+ },
+ "ramsey/composer-repl": {
+ "includes": [
+ "repl.php"
+ ]
+ },
+ "ramsey/conventional-commits": {
+ "configFile": "conventional-commits.json"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Ramsey\\Dev\\Repl\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ben Ramsey",
+ "email": "ben@benramsey.com",
+ "homepage": "https://benramsey.com"
+ }
+ ],
+ "description": "The library behind ramsey/composer-repl, allowing for extension of the ramsey/composer-repl Composer plugin and non-plugin use of the repl command.",
+ "keywords": [
+ "REPL",
+ "psysh",
+ "shell"
+ ],
+ "support": {
+ "issues": "https://github.com/ramsey/composer-repl-lib/issues",
+ "source": "https://github.com/ramsey/composer-repl-lib/tree/1.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/ramsey",
+ "type": "github"
+ }
+ ],
+ "time": "2022-04-17T01:54:57+00:00"
+ },
+ {
+ "name": "react/promise",
+ "version": "v2.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/234f8fd1023c9158e2314fa9d7d0e6a83db42910",
+ "reference": "234f8fd1023c9158e2314fa9d7d0e6a83db42910",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise/issues",
+ "source": "https://github.com/reactphp/promise/tree/v2.9.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/WyriHaximus",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2022-02-11T10:27:51+00:00"
+ },
{
"name": "sebastian/cli-parser",
"version": "1.0.1",
@@ -4969,6 +5695,115 @@
],
"time": "2022-04-01T13:37:23+00:00"
},
+ {
+ "name": "seld/phar-utils",
+ "version": "1.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/phar-utils.git",
+ "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/ea2f4014f163c1be4c601b9b7bd6af81ba8d701c",
+ "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Seld\\PharUtils\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be"
+ }
+ ],
+ "description": "PHAR file format utilities, for when PHP phars you up",
+ "keywords": [
+ "phar"
+ ],
+ "support": {
+ "issues": "https://github.com/Seldaek/phar-utils/issues",
+ "source": "https://github.com/Seldaek/phar-utils/tree/1.2.1"
+ },
+ "time": "2022-08-31T10:31:18+00:00"
+ },
+ {
+ "name": "seld/signal-handler",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/signal-handler.git",
+ "reference": "f69d119511dc0360440cdbdaa71829c149b7be75"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/signal-handler/zipball/f69d119511dc0360440cdbdaa71829c149b7be75",
+ "reference": "f69d119511dc0360440cdbdaa71829c149b7be75",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1",
+ "phpstan/phpstan-deprecation-rules": "^1.0",
+ "phpstan/phpstan-phpunit": "^1",
+ "phpstan/phpstan-strict-rules": "^1.3",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.23",
+ "psr/log": "^1 || ^2 || ^3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Seld\\Signal\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Simple unix signal handler that silently fails where signals are not supported for easy cross-platform development",
+ "keywords": [
+ "posix",
+ "sigint",
+ "signal",
+ "sigterm",
+ "unix"
+ ],
+ "support": {
+ "issues": "https://github.com/Seldaek/signal-handler/issues",
+ "source": "https://github.com/Seldaek/signal-handler/tree/2.0.1"
+ },
+ "time": "2022-07-20T18:31:45+00:00"
+ },
{
"name": "slevomat/coding-standard",
"version": "8.4.0",
@@ -6171,6 +7006,94 @@
],
"time": "2022-08-12T17:03:11+00:00"
},
+ {
+ "name": "symfony/var-dumper",
+ "version": "v6.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/var-dumper.git",
+ "reference": "d5a5e44a2260c5eb5e746bf4f1fbd12ee6ceb427"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/d5a5e44a2260c5eb5e746bf4f1fbd12ee6ceb427",
+ "reference": "d5a5e44a2260c5eb5e746bf4f1fbd12ee6ceb427",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/polyfill-mbstring": "~1.0"
+ },
+ "conflict": {
+ "phpunit/phpunit": "<5.4.3",
+ "symfony/console": "<5.4"
+ },
+ "require-dev": {
+ "ext-iconv": "*",
+ "symfony/console": "^5.4|^6.0",
+ "symfony/process": "^5.4|^6.0",
+ "symfony/uid": "^5.4|^6.0",
+ "twig/twig": "^2.13|^3.0.4"
+ },
+ "suggest": {
+ "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
+ "ext-intl": "To show region name in time zone dump",
+ "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
+ },
+ "bin": [
+ "Resources/bin/var-dump-server"
+ ],
+ "type": "library",
+ "autoload": {
+ "files": [
+ "Resources/functions/dump.php"
+ ],
+ "psr-4": {
+ "Symfony\\Component\\VarDumper\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides mechanisms for walking through any arbitrary PHP variable",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "debug",
+ "dump"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/var-dumper/tree/v6.1.3"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-07-20T13:46:29+00:00"
+ },
{
"name": "theseer/tokenizer",
"version": "1.2.1",
@@ -6449,5 +7372,5 @@
"ext-json": "*"
},
"platform-dev": [],
- "plugin-api-version": "2.3.0"
+ "plugin-api-version": "2.2.0"
}
From 28f509bd91722598d2c63c9063ddb580883e74c3 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Tue, 13 Sep 2022 22:20:56 -0500
Subject: [PATCH 39/74] chore: update composer lock file
---
composer.lock | 231 ++++++++++++++++++++++++--------------------------
1 file changed, 112 insertions(+), 119 deletions(-)
diff --git a/composer.lock b/composer.lock
index 14ccad8..634dda8 100644
--- a/composer.lock
+++ b/composer.lock
@@ -2570,16 +2570,16 @@
},
{
"name": "paragonie/sodium_compat",
- "version": "v1.17.1",
+ "version": "v1.18.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/sodium_compat.git",
- "reference": "ac994053faac18d386328c91c7900f930acadf1e"
+ "reference": "906e0b925895d3a5941eda25f371fbafb3cbc22f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/ac994053faac18d386328c91c7900f930acadf1e",
- "reference": "ac994053faac18d386328c91c7900f930acadf1e",
+ "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/906e0b925895d3a5941eda25f371fbafb3cbc22f",
+ "reference": "906e0b925895d3a5941eda25f371fbafb3cbc22f",
"shasum": ""
},
"require": {
@@ -2650,9 +2650,9 @@
],
"support": {
"issues": "https://github.com/paragonie/sodium_compat/issues",
- "source": "https://github.com/paragonie/sodium_compat/tree/v1.17.1"
+ "source": "https://github.com/paragonie/sodium_compat/tree/v1.18.0"
},
- "time": "2022-03-23T19:32:04+00:00"
+ "time": "2022-09-13T20:54:27+00:00"
},
{
"name": "phar-io/manifest",
@@ -4080,22 +4080,27 @@
},
{
"name": "psr/container",
- "version": "1.1.2",
+ "version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
- "reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
- "reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"shasum": ""
},
"require": {
"php": ">=7.4.0"
},
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
@@ -4122,22 +4127,22 @@
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
- "source": "https://github.com/php-fig/container/tree/1.1.2"
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
},
- "time": "2021-11-05T16:50:12+00:00"
+ "time": "2021-11-05T16:47:00+00:00"
},
{
"name": "psr/log",
- "version": "2.0.0",
+ "version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376"
+ "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/ef29f6d262798707a9edd554e2b82517ef3a9376",
- "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
+ "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
"shasum": ""
},
"require": {
@@ -4146,7 +4151,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "3.x-dev"
}
},
"autoload": {
@@ -4172,9 +4177,9 @@
"psr-3"
],
"support": {
- "source": "https://github.com/php-fig/log/tree/2.0.0"
+ "source": "https://github.com/php-fig/log/tree/3.0.0"
},
- "time": "2021-07-14T16:41:46+00:00"
+ "time": "2021-07-14T16:46:02+00:00"
},
{
"name": "psy/psysh",
@@ -5923,46 +5928,42 @@
},
{
"name": "symfony/console",
- "version": "v5.4.12",
+ "version": "v6.0.12",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1"
+ "reference": "c5c2e313aa682530167c25077d6bdff36346251e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/c072aa8f724c3af64e2c7a96b796a4863d24dba1",
- "reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1",
+ "url": "https://api.github.com/repos/symfony/console/zipball/c5c2e313aa682530167c25077d6bdff36346251e",
+ "reference": "c5c2e313aa682530167c25077d6bdff36346251e",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
+ "php": ">=8.0.2",
"symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php73": "^1.9",
- "symfony/polyfill-php80": "^1.16",
"symfony/service-contracts": "^1.1|^2|^3",
- "symfony/string": "^5.1|^6.0"
+ "symfony/string": "^5.4|^6.0"
},
"conflict": {
- "psr/log": ">=3",
- "symfony/dependency-injection": "<4.4",
- "symfony/dotenv": "<5.1",
- "symfony/event-dispatcher": "<4.4",
- "symfony/lock": "<4.4",
- "symfony/process": "<4.4"
+ "symfony/dependency-injection": "<5.4",
+ "symfony/dotenv": "<5.4",
+ "symfony/event-dispatcher": "<5.4",
+ "symfony/lock": "<5.4",
+ "symfony/process": "<5.4"
},
"provide": {
- "psr/log-implementation": "1.0|2.0"
+ "psr/log-implementation": "1.0|2.0|3.0"
},
"require-dev": {
- "psr/log": "^1|^2",
- "symfony/config": "^4.4|^5.0|^6.0",
- "symfony/dependency-injection": "^4.4|^5.0|^6.0",
- "symfony/event-dispatcher": "^4.4|^5.0|^6.0",
- "symfony/lock": "^4.4|^5.0|^6.0",
- "symfony/process": "^4.4|^5.0|^6.0",
- "symfony/var-dumper": "^4.4|^5.0|^6.0"
+ "psr/log": "^1|^2|^3",
+ "symfony/config": "^5.4|^6.0",
+ "symfony/dependency-injection": "^5.4|^6.0",
+ "symfony/event-dispatcher": "^5.4|^6.0",
+ "symfony/lock": "^5.4|^6.0",
+ "symfony/process": "^5.4|^6.0",
+ "symfony/var-dumper": "^5.4|^6.0"
},
"suggest": {
"psr/log": "For using the console logger",
@@ -6002,7 +6003,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v5.4.12"
+ "source": "https://github.com/symfony/console/tree/v6.0.12"
},
"funding": [
{
@@ -6018,29 +6019,29 @@
"type": "tidelift"
}
],
- "time": "2022-08-17T13:18:05+00:00"
+ "time": "2022-08-23T20:52:30+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v2.5.2",
+ "version": "v3.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66"
+ "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
- "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
+ "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
"shasum": ""
},
"require": {
- "php": ">=7.1"
+ "php": ">=8.0.2"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.5-dev"
+ "dev-main": "3.0-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -6069,7 +6070,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.2"
},
"funding": [
{
@@ -6085,27 +6086,26 @@
"type": "tidelift"
}
],
- "time": "2022-01-02T09:53:40+00:00"
+ "time": "2022-01-02T09:55:41+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v5.4.12",
+ "version": "v6.0.12",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447"
+ "reference": "a36b782dc19dce3ab7e47d4b92b13cefb3511da3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/2d67c1f9a1937406a9be3171b4b22250c0a11447",
- "reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/a36b782dc19dce3ab7e47d4b92b13cefb3511da3",
+ "reference": "a36b782dc19dce3ab7e47d4b92b13cefb3511da3",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
+ "php": ">=8.0.2",
"symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-mbstring": "~1.8",
- "symfony/polyfill-php80": "^1.16"
+ "symfony/polyfill-mbstring": "~1.8"
},
"type": "library",
"autoload": {
@@ -6133,7 +6133,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v5.4.12"
+ "source": "https://github.com/symfony/filesystem/tree/v6.0.12"
},
"funding": [
{
@@ -6149,26 +6149,24 @@
"type": "tidelift"
}
],
- "time": "2022-08-02T13:48:16+00:00"
+ "time": "2022-08-02T16:01:06+00:00"
},
{
"name": "symfony/finder",
- "version": "v5.4.11",
+ "version": "v6.0.11",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c"
+ "reference": "09cb683ba5720385ea6966e5e06be2a34f2568b1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/7872a66f57caffa2916a584db1aa7f12adc76f8c",
- "reference": "7872a66f57caffa2916a584db1aa7f12adc76f8c",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/09cb683ba5720385ea6966e5e06be2a34f2568b1",
+ "reference": "09cb683ba5720385ea6966e5e06be2a34f2568b1",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-php80": "^1.16"
+ "php": ">=8.0.2"
},
"type": "library",
"autoload": {
@@ -6196,7 +6194,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v5.4.11"
+ "source": "https://github.com/symfony/finder/tree/v6.0.11"
},
"funding": [
{
@@ -6212,27 +6210,25 @@
"type": "tidelift"
}
],
- "time": "2022-07-29T07:37:50+00:00"
+ "time": "2022-07-29T07:39:48+00:00"
},
{
"name": "symfony/options-resolver",
- "version": "v5.4.11",
+ "version": "v6.0.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
- "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690"
+ "reference": "51f7006670febe4cbcbae177cbffe93ff833250d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/54f14e36aa73cb8f7261d7686691fd4d75ea2690",
- "reference": "54f14e36aa73cb8f7261d7686691fd4d75ea2690",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/51f7006670febe4cbcbae177cbffe93ff833250d",
+ "reference": "51f7006670febe4cbcbae177cbffe93ff833250d",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-php73": "~1.0",
- "symfony/polyfill-php80": "^1.16"
+ "php": ">=8.0.2",
+ "symfony/deprecation-contracts": "^2.1|^3"
},
"type": "library",
"autoload": {
@@ -6265,7 +6261,7 @@
"options"
],
"support": {
- "source": "https://github.com/symfony/options-resolver/tree/v5.4.11"
+ "source": "https://github.com/symfony/options-resolver/tree/v6.0.3"
},
"funding": [
{
@@ -6281,7 +6277,7 @@
"type": "tidelift"
}
],
- "time": "2022-07-20T13:00:38+00:00"
+ "time": "2022-01-02T09:55:41+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -6777,21 +6773,20 @@
},
{
"name": "symfony/process",
- "version": "v5.4.11",
+ "version": "v6.0.11",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1"
+ "reference": "44270a08ccb664143dede554ff1c00aaa2247a43"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/6e75fe6874cbc7e4773d049616ab450eff537bf1",
- "reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1",
+ "url": "https://api.github.com/repos/symfony/process/zipball/44270a08ccb664143dede554ff1c00aaa2247a43",
+ "reference": "44270a08ccb664143dede554ff1c00aaa2247a43",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/polyfill-php80": "^1.16"
+ "php": ">=8.0.2"
},
"type": "library",
"autoload": {
@@ -6819,7 +6814,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v5.4.11"
+ "source": "https://github.com/symfony/process/tree/v6.0.11"
},
"funding": [
{
@@ -6835,26 +6830,25 @@
"type": "tidelift"
}
],
- "time": "2022-06-27T16:58:25+00:00"
+ "time": "2022-06-27T17:10:44+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v2.5.2",
+ "version": "v3.0.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c"
+ "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
- "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d78d39c1599bd1188b8e26bb341da52c3c6d8a66",
+ "reference": "d78d39c1599bd1188b8e26bb341da52c3c6d8a66",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "psr/container": "^1.1",
- "symfony/deprecation-contracts": "^2.1|^3"
+ "php": ">=8.0.2",
+ "psr/container": "^2.0"
},
"conflict": {
"ext-psr": "<1.1|>=2"
@@ -6865,7 +6859,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "2.5-dev"
+ "dev-main": "3.0-dev"
},
"thanks": {
"name": "symfony/contracts",
@@ -6902,7 +6896,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v2.5.2"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.0.2"
},
"funding": [
{
@@ -6918,38 +6912,37 @@
"type": "tidelift"
}
],
- "time": "2022-05-30T19:17:29+00:00"
+ "time": "2022-05-30T19:17:58+00:00"
},
{
"name": "symfony/string",
- "version": "v5.4.12",
+ "version": "v6.0.12",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "2fc515e512d721bf31ea76bd02fe23ada4640058"
+ "reference": "3a975ba1a1508ad97df45f4590f55b7cc4c1a0a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/2fc515e512d721bf31ea76bd02fe23ada4640058",
- "reference": "2fc515e512d721bf31ea76bd02fe23ada4640058",
+ "url": "https://api.github.com/repos/symfony/string/zipball/3a975ba1a1508ad97df45f4590f55b7cc4c1a0a0",
+ "reference": "3a975ba1a1508ad97df45f4590f55b7cc4c1a0a0",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
+ "php": ">=8.0.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-intl-grapheme": "~1.0",
"symfony/polyfill-intl-normalizer": "~1.0",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php80": "~1.15"
+ "symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
- "symfony/translation-contracts": ">=3.0"
+ "symfony/translation-contracts": "<2.0"
},
"require-dev": {
- "symfony/error-handler": "^4.4|^5.0|^6.0",
- "symfony/http-client": "^4.4|^5.0|^6.0",
- "symfony/translation-contracts": "^1.1|^2",
- "symfony/var-exporter": "^4.4|^5.0|^6.0"
+ "symfony/error-handler": "^5.4|^6.0",
+ "symfony/http-client": "^5.4|^6.0",
+ "symfony/translation-contracts": "^2.0|^3.0",
+ "symfony/var-exporter": "^5.4|^6.0"
},
"type": "library",
"autoload": {
@@ -6988,7 +6981,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v5.4.12"
+ "source": "https://github.com/symfony/string/tree/v6.0.12"
},
"funding": [
{
@@ -7004,24 +6997,24 @@
"type": "tidelift"
}
],
- "time": "2022-08-12T17:03:11+00:00"
+ "time": "2022-08-12T18:05:20+00:00"
},
{
"name": "symfony/var-dumper",
- "version": "v6.1.3",
+ "version": "v6.0.11",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "d5a5e44a2260c5eb5e746bf4f1fbd12ee6ceb427"
+ "reference": "2672bdc01c1971e3d8879ce153ec4c3621be5f07"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/d5a5e44a2260c5eb5e746bf4f1fbd12ee6ceb427",
- "reference": "d5a5e44a2260c5eb5e746bf4f1fbd12ee6ceb427",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2672bdc01c1971e3d8879ce153ec4c3621be5f07",
+ "reference": "2672bdc01c1971e3d8879ce153ec4c3621be5f07",
"shasum": ""
},
"require": {
- "php": ">=8.1",
+ "php": ">=8.0.2",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
@@ -7076,7 +7069,7 @@
"dump"
],
"support": {
- "source": "https://github.com/symfony/var-dumper/tree/v6.1.3"
+ "source": "https://github.com/symfony/var-dumper/tree/v6.0.11"
},
"funding": [
{
@@ -7092,7 +7085,7 @@
"type": "tidelift"
}
],
- "time": "2022-07-20T13:46:29+00:00"
+ "time": "2022-07-20T13:45:53+00:00"
},
{
"name": "theseer/tokenizer",
From 4f4deb1dd6ca3f9522093c98327fde676bc4dbe7 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 14 Sep 2022 18:21:10 -0500
Subject: [PATCH 40/74] feat: add UUIDv7 documentation and customization
---
docs/customize/ordered-time-codec.rst | 8 +-
docs/customize/timestamp-first-comb-codec.rst | 7 +
docs/database.rst | 23 ++-
docs/introduction.rst | 7 +-
docs/quickstart.rst | 2 +
docs/reference.rst | 1 +
docs/reference/rfc4122-uuidv7.rst | 20 ++
docs/rfc4122.rst | 16 +-
docs/rfc4122/version1.rst | 6 +
docs/rfc4122/version6.rst | 8 +-
docs/rfc4122/version7.rst | 173 ++++++++++++++++++
src/Uuid.php | 8 +-
src/UuidFactory.php | 27 ++-
src/functions.php | 15 ++
.../Converter/Time/UnixTimeConverterTest.php | 4 +-
tests/FunctionsTest.php | 39 +++-
tests/UuidTest.php | 15 ++
17 files changed, 348 insertions(+), 31 deletions(-)
create mode 100644 docs/reference/rfc4122-uuidv7.rst
create mode 100644 docs/rfc4122/version7.rst
diff --git a/docs/customize/ordered-time-codec.rst b/docs/customize/ordered-time-codec.rst
index b71a7eb..a25c5c7 100644
--- a/docs/customize/ordered-time-codec.rst
+++ b/docs/customize/ordered-time-codec.rst
@@ -4,10 +4,12 @@
Ordered-time Codec
==================
-.. hint::
+.. attention::
- :ref:`Version 6, reordered time UUIDs ` are a
- new version of UUID that take the place of ordered-time UUIDs.
+ :ref:`Version 6, reordered time UUIDs ` are a new version
+ of UUID that eliminate the need for the ordered-time codec. If you aren't
+ currently using the ordered-time codec, and you need time-based, sortable
+ UUIDs, consider using version 6 UUIDs.
UUIDs arrange their bytes according to the standard recommended by `RFC 4122`_.
Unfortunately, this means the bytes aren't in an arrangement that supports
diff --git a/docs/customize/timestamp-first-comb-codec.rst b/docs/customize/timestamp-first-comb-codec.rst
index 00f3377..5ca42a9 100644
--- a/docs/customize/timestamp-first-comb-codec.rst
+++ b/docs/customize/timestamp-first-comb-codec.rst
@@ -4,6 +4,13 @@
Timestamp-first COMB Codec
==========================
+.. attention::
+
+ :ref:`Version 7, Unix Epoch time UUIDs ` are a new version
+ of UUID that eliminate the need for the timestamp-first COMB codec. If you
+ aren't currently using the timestamp-first COMB codec, and you need
+ time-based, sortable UUIDs, consider using version 7 UUIDs.
+
:ref:`Version 4, random UUIDs ` are doubly problematic when it
comes to sorting and storing to databases (see :ref:`database.order`), since
their values are random, and there is no timestamp associated with them that may
diff --git a/docs/database.rst b/docs/database.rst
index 9459862..ee401e3 100644
--- a/docs/database.rst
+++ b/docs/database.rst
@@ -229,29 +229,28 @@ small.
Insertion Order and Sorting
###########################
-UUIDs are not *monotonically increasing*. Even time-based UUIDs are not. If
-using UUIDs as primary keys, the inserts will be random, and the data will be
+UUID versions 1, 2, 3, 4, and 5 are not *monotonically increasing*. If using
+these versions as primary keys, the inserts will be random, and the data will be
scattered on disk (for InnoDB). Over time, as the database size grows, lookups
will become slower and slower.
-.. note::
+.. tip::
See Percona's "`Storing UUID Values in MySQL`_" post, for more details on
the performance of UUIDs as primary keys.
To minimize these problems, two solutions have been devised:
-1. Timestamp first COMBs
-2. Ordered-time UUIDs
+1. :ref:`rfc4122.version6` UUIDs
+2. :ref:`rfc4122.version7` UUIDs
-:ref:`customize.timestamp-first-comb-codec` explains the first solution and how
-to use ramsey/uuid to implement it, while :ref:`customize.ordered-time-codec`
-explains how to use ramsey/uuid to implement the second solution.
+.. note::
-.. hint::
-
- :ref:`Version 6, reordered time UUIDs ` are a
- new version of UUID that take the place of ordered-time UUIDs.
+ We previously recommended the use of the :ref:`timestamp-first COMB
+ ` or :ref:`ordered-time
+ ` codecs to solve these problems. However,
+ UUID versions 6 and 7 were defined to provide these solutions in a
+ standardized way.
.. _ramsey/uuid-doctrine: https://github.com/ramsey/uuid-doctrine
diff --git a/docs/introduction.rst b/docs/introduction.rst
index 380f66b..5cb2dbd 100644
--- a/docs/introduction.rst
+++ b/docs/introduction.rst
@@ -5,9 +5,9 @@ Introduction
============
ramsey/uuid is a PHP library for generating and working with `RFC 4122`_ version
-1, 2, 3, 4, and 5 universally unique identifiers (UUID). ramsey/uuid also
-supports optional and non-standard features, such as `version 6 UUIDs`_,
-GUIDs, and other approaches for encoding/decoding UUIDs.
+1, 2, 3, 4, 5, 6, and 7 universally unique identifiers (UUID). ramsey/uuid also
+supports optional and non-standard features, such as GUIDs and other approaches
+for encoding/decoding UUIDs.
What Is a UUID?
###############
@@ -29,4 +29,3 @@ UUIDs can also be stored in binary format, as a string of 16 bytes.
.. _RFC 4122: https://tools.ietf.org/html/rfc4122
-.. _version 6 UUIDs: http://gh.peabody.io/uuidv6/
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index 871fd1c..bdc310e 100644
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -97,6 +97,8 @@ library.
- This generates a :ref:`rfc4122.version5` UUID.
* - :php:meth:`Uuid::uuid6() `
- This generates a :ref:`rfc4122.version6` UUID.
+ * - :php:meth:`Uuid::uuid7() `
+ - This generates a :ref:`rfc4122.version7` UUID.
* - :php:meth:`Uuid::isValid() `
- Checks whether a string is a valid UUID.
* - :php:meth:`Uuid::fromString() `
diff --git a/docs/reference.rst b/docs/reference.rst
index b04e1bd..55d5c9e 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -18,6 +18,7 @@ Reference
reference/rfc4122-uuidv4
reference/rfc4122-uuidv5
reference/rfc4122-uuidv6
+ reference/rfc4122-uuidv7
reference/guid-fields
reference/guid-guid
reference/nonstandard-fields
diff --git a/docs/reference/rfc4122-uuidv7.rst b/docs/reference/rfc4122-uuidv7.rst
new file mode 100644
index 0000000..e4041a8
--- /dev/null
+++ b/docs/reference/rfc4122-uuidv7.rst
@@ -0,0 +1,20 @@
+.. _reference.rfc4122.uuidv7:
+
+===============
+Rfc4122\\UuidV7
+===============
+
+.. php:namespace:: Ramsey\Uuid\Rfc4122
+
+.. php:class:: UuidV7
+
+ Implements :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface`.
+
+ UuidV7 represents a :ref:`version 7, Unix Epoch time UUID `.
+ In addition to providing the methods defined on the interface, this class
+ additionally provides the following methods.
+
+ .. php:method:: getDateTime()
+
+ :returns: A date object representing the timestamp associated with the UUID.
+ :returntype: ``\DateTimeInterface``
diff --git a/docs/rfc4122.rst b/docs/rfc4122.rst
index d6c19d6..2520f97 100644
--- a/docs/rfc4122.rst
+++ b/docs/rfc4122.rst
@@ -14,11 +14,12 @@ RFC 4122 UUIDs
rfc4122/version4
rfc4122/version5
rfc4122/version6
+ rfc4122/version7
-`RFC 4122`_ defines five versions of UUID. Each version has different generation
-algorithms and properties. Which one you choose to use depends on your use-case.
-You can find out more about their applications on the specific page for that
-version.
+`RFC 4122`_ defines five versions of UUID, while a `new Internet-Draft under
+review`_ defines three new versions. Each version has different generation
+algorithms and properties. Which one you choose depends on your use-case. You
+can find out more about their applications on the specific page for that version.
Version 1: Gregorian Time
This version of UUID combines a timestamp, node value (in the form of a MAC
@@ -50,5 +51,12 @@ Version 6: Reordered Time
:ref:`version 1 UUID ` with a *monotonically increasing*
UUID. For more details, see :ref:`rfc4122.version6`.
+Version 7: Unix Epoch Time
+ This version of UUID combines a timestamp--based on milliseconds elapsed
+ since the Unix Epoch--and random bytes to create a monotonically increasing,
+ sortable UUID without the privacy and entropy concerns associated with
+ version 1 and version 6 UUIDs. For more details, see :ref:`rfc4122.version7`.
+
.. _RFC 4122: https://tools.ietf.org/html/rfc4122
+.. _new Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04
diff --git a/docs/rfc4122/version1.rst b/docs/rfc4122/version1.rst
index 8ac3147..b71a196 100644
--- a/docs/rfc4122/version1.rst
+++ b/docs/rfc4122/version1.rst
@@ -4,6 +4,12 @@
Version 1: Gregorian Time
=========================
+.. attention::
+
+ If you need a time-based UUID, and you don't need the other features
+ included in version 1 UUIDs, we recommend using
+ :ref:`version 7 UUIDs `.
+
A version 1 UUID uses the current time, along with the MAC address (or *node*)
for a network interface on the local machine. This serves two purposes:
diff --git a/docs/rfc4122/version6.rst b/docs/rfc4122/version6.rst
index 49e3ccf..e4b79bb 100644
--- a/docs/rfc4122/version6.rst
+++ b/docs/rfc4122/version6.rst
@@ -11,6 +11,12 @@ Version 6: Reordered Time
through the IETF process, the version 6 format is not expected to change
in any way that breaks compatibility.
+.. attention::
+
+ If you need a time-based UUID, and you don't need the other features
+ included in version 6 UUIDs, we recommend using
+ :ref:`version 7 UUIDs `.
+
Version 6 UUIDs solve `two problems that have long existed`_ with the use of
:ref:`version 1 ` UUIDs:
@@ -199,7 +205,7 @@ machines, see :ref:`rfc4122.version6.nodes`.
If you do not need an identifier with a node value embedded in it, but you still
need the benefit of a monotonically increasing unique identifier, see
-:ref:`customize.timestamp-first-comb-codec`.
+:ref:`rfc4122.version7`.
.. _Internet-Draft under review: https://datatracker.ietf.org/doc/draft-peabody-dispatch-new-uuid-format/
diff --git a/docs/rfc4122/version7.rst b/docs/rfc4122/version7.rst
new file mode 100644
index 0000000..1143c7c
--- /dev/null
+++ b/docs/rfc4122/version7.rst
@@ -0,0 +1,173 @@
+.. _rfc4122.version7:
+
+==========================
+Version 7: Unix Epoch Time
+==========================
+
+.. note::
+
+ Version 7, Unix Epoch time UUIDs are a new format of UUID, proposed in an
+ `Internet-Draft under review`_ at the IETF. While the draft is still going
+ through the IETF process, the version 7 format is not expected to change
+ in any way that breaks compatibility.
+
+.. admonition:: ULIDs and Version 7 UUIDs
+ :class: hint
+
+ Version 7 UUIDs are binary-compatible with `ULIDs`_ (universally unique
+ lexicographically-sortable identifiers).
+
+ Both use a 48-bit timestamp in milliseconds since the Unix Epoch, filling
+ the rest with random data. Version 7 UUIDs then add the version and variant
+ bits required by the UUID specification, which reduces the randomness from
+ 80 bits to 74. Otherwise, they are identical.
+
+ You may even convert a version 7 UUID to a ULID.
+ :ref:`See below for an example. `
+
+Version 7 UUIDs solve `two problems that have long existed`_ with the use of
+:ref:`version 1 ` UUIDs:
+
+1. Scattered database records
+2. Inability to sort by an identifier in a meaningful way (i.e., insert order)
+
+To overcome these issues, we need the ability to generate UUIDs that are
+*monotonically increasing*.
+
+:ref:`Version 6 UUIDs ` provide an excellent solution for
+those who need monotonically increasing, sortable UUIDs with the features of
+version 1 UUIDs (MAC address and clock sequence), but if those features aren't
+necessary for your application, using a version 6 UUID might be overkill.
+
+Version 7 UUIDs combine random data (like version 4 UUIDs) with a timestamp (in
+milliseconds since the Unix Epoch, i.e., 1970-01-01 00:00:00 UTC) to create a
+monotonically increasing, sortable UUID that doesn't have any privacy concerns,
+since it doesn't include a MAC address.
+
+For this reason, implementations should use version 7 UUIDs over versions 1 and
+6, if possible.
+
+.. code-block:: php
+ :caption: Generate a version 7, Unix Epoch time UUID
+ :name: rfc4122.version7.example
+
+ use Ramsey\Uuid\Uuid;
+
+ $uuid = Uuid::uuid7();
+
+ printf(
+ "UUID: %s\nVersion: %d\nDate: %s\n",
+ $uuid->toString(),
+ $uuid->getFields()->getVersion(),
+ $uuid->getDateTime()->format('r'),
+ );
+
+This will generate a version 7 UUID and print out its string representation and
+the time it was created.
+
+It will look something like this:
+
+.. code-block:: text
+
+ UUID: 01833ce0-3486-7bfd-84a1-ad157cf64005
+ Version: 7
+ Date: Wed, 14 Sep 2022 16:41:10 +0000
+
+To use an existing date and time to generate a version 7 UUID, you may pass a
+``\DateTimeInterface`` instance to the ``uuid7()`` method.
+
+.. code-block:: php
+ :caption: Generate a version 7 UUID from an existing date and time
+ :name: rfc4122.version7.example-datetime
+
+ use DateTimeImmutable;
+ use Ramsey\Uuid\Uuid;
+
+ $dateTime = new DateTimeImmutable('@281474976710.655');
+ $uuid = Uuid::uuid7($dateTime);
+
+ printf(
+ "UUID: %s\nVersion: %d\nDate: %s\n",
+ $uuid->toString(),
+ $uuid->getFields()->getVersion(),
+ $uuid->getDateTime()->format('r'),
+ );
+
+Which will print something like this:
+
+.. code-block:: text
+
+ UUID: ffffffff-ffff-7964-a8f6-001336ac20cb
+ Version: 7
+ Date: Tue, 02 Aug 10889 05:31:50 +0000
+
+.. tip::
+
+ Version 7 UUIDs generated in ramsey/uuid are instances of UuidV7. Check out
+ the :php:class:`Ramsey\\Uuid\\Rfc4122\\UuidV7` API documentation to learn
+ more about what you can do with a UuidV7 instance.
+
+
+.. _rfc4122.version7.ulid:
+
+Convert a Version 7 UUID to a ULID
+##################################
+
+As mentioned in the callout above, version 7 UUIDs are binary-compatible with
+`ULIDs`_. This means you can encode a version 7 UUID using `Crockford's Base 32
+algorithm`_ and it will be a valid ULID, timestamp and all.
+
+Using the third-party library `tuupola/base32`_, here's how we can encode a
+version 7 UUID as a ULID. Note that there's a little bit of work to perform the
+conversion, since you're working with different bases.
+
+.. code-block:: php
+ :caption: Encode a version 7, Unix Epoch time UUID as a ULID
+ :name: rfc4122.version7.example-ulid
+
+ use Ramsey\Uuid\Uuid;
+ use Tuupola\Base32;
+
+ $crockford = new Base32([
+ 'characters' => Base32::CROCKFORD,
+ 'padding' => false,
+ 'crockford' => true,
+ ]);
+
+ $uuid = Uuid::uuid7();
+
+ // First, we must pad the 16-byte string to 20 bytes
+ // for proper conversion without data loss.
+ $bytes = str_pad($uuid->getBytes(), 20, "\x00", STR_PAD_LEFT);
+
+ // Use Crockford's Base 32 encoding algorithm.
+ $encoded = $crockford->encode($bytes);
+
+ // That 20-byte string was encoded to 32 characters to avoid loss
+ // of data. We must strip off the first 6 characters--which are
+ // all zeros--to get a valid 26-character ULID string.
+ $ulid = substr($encoded, 6);
+
+ printf("ULID: %s\n", $ulid);
+
+This will print something like this:
+
+.. code-block:: text
+
+ ULID: 01GCZ05N3JFRKBRWKNGCQZGP44
+
+.. caution::
+
+ Be aware that all version 7 UUIDs may be converted to ULIDs but not all
+ ULIDs may be converted to UUIDs.
+
+ For that matter, all UUIDs of any version may be encoded as ULIDs, but they
+ will not be monotonically increasing and sortable unless they are version 7
+ UUIDs. You will also not be able to extract a meaningful timestamp from the
+ ULID, unless it was converted from a version 7 UUID.
+
+.. _ULIDs: https://github.com/ulid/spec
+.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2
+.. _two problems that have long existed: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
+.. _Crockford's Base 32 algorithm: https://www.crockford.com/base32.html
+.. _tuupola/base32: https://packagist.org/packages/tuupola/base32
diff --git a/src/Uuid.php b/src/Uuid.php
index ee04da8..0397de1 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -683,16 +683,20 @@ class Uuid implements UuidInterface
/**
* Returns a version 7 (Unix Epoch time) UUID
*
+ * @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 static function uuid7(): UuidInterface
+ public static function uuid7(?DateTimeInterface $dateTime = null): UuidInterface
{
$factory = self::getFactory();
if (method_exists($factory, 'uuid7')) {
/** @var UuidInterface */
- return $factory->uuid7();
+ return $factory->uuid7($dateTime);
}
throw new UnsupportedOperationException(
diff --git a/src/UuidFactory.php b/src/UuidFactory.php
index de3707c..f4fabdd 100644
--- a/src/UuidFactory.php
+++ b/src/UuidFactory.php
@@ -18,13 +18,16 @@ use DateTimeInterface;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Converter\Time\UnixTimeConverter;
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\Generator\UnixTimeGenerator;
use Ramsey\Uuid\Lazy\LazyUuidFromString;
+use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Provider\Time\FixedTimeProvider;
use Ramsey\Uuid\Type\Hexadecimal;
@@ -421,12 +424,32 @@ class UuidFactory implements UuidFactoryInterface
/**
* Returns a version 7 (Unix Epoch time) UUID
*
+ * @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(): UuidInterface
+ public function uuid7(?DateTimeInterface $dateTime = null): UuidInterface
{
- return $this->uuidFromBytesAndVersion($this->unixTimeGenerator->generate(), Uuid::UUID_TYPE_UNIX_TIME);
+ if ($dateTime !== null) {
+ $timeProvider = new FixedTimeProvider(
+ new Time($dateTime->format('U'), $dateTime->format('u'))
+ );
+
+ $timeGenerator = new UnixTimeGenerator(
+ new UnixTimeConverter(new BrickMathCalculator()),
+ $timeProvider,
+ $this->randomGenerator,
+ );
+
+ $bytes = $timeGenerator->generate();
+ } else {
+ $bytes = $this->unixTimeGenerator->generate();
+ }
+
+ return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_UNIX_TIME);
}
/**
diff --git a/src/functions.php b/src/functions.php
index c3d3b49..fa80f4e 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -15,6 +15,7 @@ declare(strict_types=1);
namespace Ramsey\Uuid;
+use DateTimeInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
@@ -121,3 +122,17 @@ function v6(?Hexadecimal $node = null, ?int $clockSeq = null): string
{
return Uuid::uuid6($node, $clockSeq)->toString();
}
+
+/**
+ * Returns a version 7 (Unix Epoch time) UUID
+ *
+ * @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 non-empty-string Version 7 UUID as a string
+ */
+function v7(?DateTimeInterface $dateTime = null): string
+{
+ return Uuid::uuid7($dateTime)->toString();
+}
diff --git a/tests/Converter/Time/UnixTimeConverterTest.php b/tests/Converter/Time/UnixTimeConverterTest.php
index 3a22f8a..2aff15f 100644
--- a/tests/Converter/Time/UnixTimeConverterTest.php
+++ b/tests/Converter/Time/UnixTimeConverterTest.php
@@ -52,7 +52,7 @@ class UnixTimeConverterTest extends TestCase
'microseconds' => '999000',
],
- // This is the last possible time supported by v7 UUIDs.
+ // This is the last possible time supported by v7 UUIDs (2 ^ 48 - 1).
// 10889-08-02 05:31:50.655 +00:00
[
'uuidTimestamp' => new Hexadecimal('ffffffffffff'),
@@ -155,7 +155,7 @@ class UnixTimeConverterTest extends TestCase
'expected' => '000000000000',
],
- // This is the last possible time supported by v7 UUIDs:
+ // This is the last possible time supported by v7 UUIDs (2 ^ 48 - 1):
// 10889-08-02 05:31:50.655 +00:00
[
'seconds' => '281474976710',
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
index 357bd4f..bd368ee 100644
--- a/tests/FunctionsTest.php
+++ b/tests/FunctionsTest.php
@@ -4,7 +4,10 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Test;
+use DateTimeImmutable;
+use DateTimeInterface;
use Ramsey\Uuid\Rfc4122\FieldsInterface;
+use Ramsey\Uuid\Rfc4122\UuidV7;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Uuid;
@@ -15,6 +18,7 @@ use function Ramsey\Uuid\v3;
use function Ramsey\Uuid\v4;
use function Ramsey\Uuid\v5;
use function Ramsey\Uuid\v6;
+use function Ramsey\Uuid\v7;
class FunctionsTest extends TestCase
{
@@ -79,6 +83,39 @@ class FunctionsTest extends TestCase
$fields = Uuid::fromString($v6)->getFields();
$this->assertIsString($v6);
- $this->assertSame(Uuid::UUID_TYPE_PEABODY, $fields->getVersion());
+ $this->assertSame(Uuid::UUID_TYPE_REORDERED_TIME, $fields->getVersion());
+ }
+
+ public function testV7ReturnsVersion7UuidString(): void
+ {
+ $v7 = v7();
+
+ /** @var UuidV7 $uuid */
+ $uuid = Uuid::fromString($v7);
+
+ /** @var FieldsInterface $fields */
+ $fields = $uuid->getFields();
+
+ $this->assertIsString($v7);
+ $this->assertSame(Uuid::UUID_TYPE_UNIX_TIME, $fields->getVersion());
+ $this->assertInstanceOf(DateTimeInterface::class, $uuid->getDateTime());
+ }
+
+ public function testV7WithCustomDateTimeReturnsVersion7UuidString(): void
+ {
+ $dateTime = new DateTimeImmutable('2022-09-14T22:44:33+00:00');
+
+ $v7 = v7($dateTime);
+
+ /** @var UuidV7 $uuid */
+ $uuid = Uuid::fromString($v7);
+
+ /** @var FieldsInterface $fields */
+ $fields = $uuid->getFields();
+
+ $this->assertIsString($v7);
+ $this->assertSame(Uuid::UUID_TYPE_UNIX_TIME, $fields->getVersion());
+ $this->assertInstanceOf(DateTimeInterface::class, $uuid->getDateTime());
+ $this->assertSame(1663195473, $uuid->getDateTime()->getTimestamp());
}
}
diff --git a/tests/UuidTest.php b/tests/UuidTest.php
index 4be8c72..5f71905 100644
--- a/tests/UuidTest.php
+++ b/tests/UuidTest.php
@@ -6,6 +6,7 @@ namespace Ramsey\Uuid\Test;
use Brick\Math\BigDecimal;
use Brick\Math\RoundingMode;
+use DateTimeImmutable;
use DateTimeInterface;
use Mockery;
use Mockery\MockInterface;
@@ -728,6 +729,20 @@ class UuidTest extends TestCase
Uuid::uuid7();
}
+ public function testUuid7WithDateTime(): void
+ {
+ $dateTime = new DateTimeImmutable('@281474976710.655');
+
+ $uuid = Uuid::uuid7($dateTime);
+ $this->assertInstanceOf(DateTimeInterface::class, $uuid->getDateTime());
+ $this->assertSame(2, $uuid->getVariant());
+ $this->assertSame(7, $uuid->getVersion());
+ $this->assertSame(
+ '10889-08-02T05:31:50.655+00:00',
+ $uuid->getDateTime()->format(DateTimeInterface::RFC3339_EXTENDED),
+ );
+ }
+
/**
* Tests known version-3 UUIDs
*
From e6164bd68736cee8f6b4837dead5ca810f3fc051 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 14 Sep 2022 18:35:44 -0500
Subject: [PATCH 41/74] docs: update copyright year on documentation
---
docs/conf.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/conf.py b/docs/conf.py
index 9976a6c..a647ad9 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -35,7 +35,7 @@ def get_version():
# -- Project information -----------------------------------------------------
project = 'ramsey/uuid'
-copyright = '2020, Ben Ramsey'
+copyright = '2012-{year}, Ben Ramsey'.format(year = datetime.date.today().strftime('%Y'))
author = 'Ben Ramsey'
version = get_version().strip()
From 685c2f3f2316fa49185b54d6b36a2cceab26ac4a Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 14 Sep 2022 20:44:24 -0500
Subject: [PATCH 42/74] feat: support max UUIDs
---
psalm-baseline.xml | 4 +-
src/Guid/Fields.php | 14 +++++--
src/Nonstandard/Fields.php | 5 +++
src/Rfc4122/Fields.php | 13 +++++--
src/Rfc4122/MaxTrait.php | 41 +++++++++++++++++++++
src/Rfc4122/MaxUuid.php | 27 ++++++++++++++
src/Rfc4122/UuidBuilder.php | 5 +++
src/Rfc4122/VariantTrait.php | 6 +++
src/Rfc4122/VersionTrait.php | 7 +++-
src/Uuid.php | 8 ++++
tests/ExpectedBehaviorTest.php | 15 ++++++--
tests/Guid/FieldsTest.php | 21 ++++++++++-
tests/Nonstandard/FieldsTest.php | 1 +
tests/Rfc4122/FieldsTest.php | 23 +++++++++++-
tests/Rfc4122/UuidBuilderTest.php | 15 +++++++-
tests/Rfc4122/VariantTraitTest.php | 4 ++
tests/UuidTest.php | 49 +++++++++++++++++++++++--
tests/benchmark/UuidGenerationBench.php | 6 +++
18 files changed, 247 insertions(+), 17 deletions(-)
create mode 100644 src/Rfc4122/MaxTrait.php
create mode 100644 src/Rfc4122/MaxUuid.php
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 96f8617..85843cc 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -96,7 +96,9 @@
-
+
+ $this
+ $this
$this
$this
$this
diff --git a/src/Guid/Fields.php b/src/Guid/Fields.php
index d8a1a2b..9e47aff 100644
--- a/src/Guid/Fields.php
+++ b/src/Guid/Fields.php
@@ -17,6 +17,7 @@ namespace Ramsey\Uuid\Guid;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Fields\SerializableFieldsTrait;
use Ramsey\Uuid\Rfc4122\FieldsInterface;
+use Ramsey\Uuid\Rfc4122\MaxTrait;
use Ramsey\Uuid\Rfc4122\NilTrait;
use Ramsey\Uuid\Rfc4122\VariantTrait;
use Ramsey\Uuid\Rfc4122\VersionTrait;
@@ -44,6 +45,7 @@ use const STR_PAD_LEFT;
*/
final class Fields implements FieldsInterface
{
+ use MaxTrait;
use NilTrait;
use SerializableFieldsTrait;
use VariantTrait;
@@ -149,7 +151,13 @@ final class Fields implements FieldsInterface
public function getClockSeq(): Hexadecimal
{
- $clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff;
+ if ($this->isMax()) {
+ $clockSeq = 0xffff;
+ } elseif ($this->isNil()) {
+ $clockSeq = 0x0000;
+ } else {
+ $clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff;
+ }
return new Hexadecimal(str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT));
}
@@ -171,7 +179,7 @@ final class Fields implements FieldsInterface
public function getVersion(): ?int
{
- if ($this->isNil()) {
+ if ($this->isNil() || $this->isMax()) {
return null;
}
@@ -183,7 +191,7 @@ final class Fields implements FieldsInterface
private function isCorrectVariant(): bool
{
- if ($this->isNil()) {
+ if ($this->isNil() || $this->isMax()) {
return true;
}
diff --git a/src/Nonstandard/Fields.php b/src/Nonstandard/Fields.php
index 927bc6a..d5b820f 100644
--- a/src/Nonstandard/Fields.php
+++ b/src/Nonstandard/Fields.php
@@ -130,4 +130,9 @@ final class Fields implements FieldsInterface
{
return false;
}
+
+ public function isMax(): bool
+ {
+ return false;
+ }
}
diff --git a/src/Rfc4122/Fields.php b/src/Rfc4122/Fields.php
index 6103cdc..0a6ece5 100644
--- a/src/Rfc4122/Fields.php
+++ b/src/Rfc4122/Fields.php
@@ -40,6 +40,7 @@ use const STR_PAD_LEFT;
*/
final class Fields implements FieldsInterface
{
+ use MaxTrait;
use NilTrait;
use SerializableFieldsTrait;
use VariantTrait;
@@ -88,7 +89,13 @@ final class Fields implements FieldsInterface
public function getClockSeq(): Hexadecimal
{
- $clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff;
+ if ($this->isMax()) {
+ $clockSeq = 0xffff;
+ } elseif ($this->isNil()) {
+ $clockSeq = 0x0000;
+ } else {
+ $clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff;
+ }
return new Hexadecimal(str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT));
}
@@ -184,7 +191,7 @@ final class Fields implements FieldsInterface
public function getVersion(): ?int
{
- if ($this->isNil()) {
+ if ($this->isNil() || $this->isMax()) {
return null;
}
@@ -196,7 +203,7 @@ final class Fields implements FieldsInterface
private function isCorrectVariant(): bool
{
- if ($this->isNil()) {
+ if ($this->isNil() || $this->isMax()) {
return true;
}
diff --git a/src/Rfc4122/MaxTrait.php b/src/Rfc4122/MaxTrait.php
new file mode 100644
index 0000000..2ec3047
--- /dev/null
+++ b/src/Rfc4122/MaxTrait.php
@@ -0,0 +1,41 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Rfc4122;
+
+/**
+ * Provides common functionality for max UUIDs
+ *
+ * The max UUID is special form of UUID that is specified to have all 128 bits
+ * set to one. It is the inverse of the nil UUID.
+ *
+ * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4 Max UUID
+ *
+ * @psalm-immutable
+ */
+trait MaxTrait
+{
+ /**
+ * Returns the bytes that comprise the fields
+ */
+ abstract public function getBytes(): string;
+
+ /**
+ * Returns true if the byte string represents a max UUID
+ */
+ public function isMax(): bool
+ {
+ return $this->getBytes() === "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
+ }
+}
diff --git a/src/Rfc4122/MaxUuid.php b/src/Rfc4122/MaxUuid.php
new file mode 100644
index 0000000..e5ffa72
--- /dev/null
+++ b/src/Rfc4122/MaxUuid.php
@@ -0,0 +1,27 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Rfc4122;
+
+use Ramsey\Uuid\Uuid;
+
+/**
+ * The max UUID is special form of UUID that is specified to have all 128 bits
+ * set to one
+ *
+ * @psalm-immutable
+ */
+final class MaxUuid extends Uuid implements UuidInterface
+{
+}
diff --git a/src/Rfc4122/UuidBuilder.php b/src/Rfc4122/UuidBuilder.php
index 10eded9..895524d 100644
--- a/src/Rfc4122/UuidBuilder.php
+++ b/src/Rfc4122/UuidBuilder.php
@@ -73,12 +73,17 @@ class UuidBuilder implements UuidBuilderInterface
public function build(CodecInterface $codec, string $bytes): UuidInterface
{
try {
+ /** @var Fields $fields */
$fields = $this->buildFields($bytes);
if ($fields->isNil()) {
return new NilUuid($fields, $this->numberConverter, $codec, $this->timeConverter);
}
+ if ($fields->isMax()) {
+ return new MaxUuid($fields, $this->numberConverter, $codec, $this->timeConverter);
+ }
+
switch ($fields->getVersion()) {
case Uuid::UUID_TYPE_TIME:
return new UuidV1($fields, $this->numberConverter, $codec, $this->timeConverter);
diff --git a/src/Rfc4122/VariantTrait.php b/src/Rfc4122/VariantTrait.php
index 4c98165..74d12ef 100644
--- a/src/Rfc4122/VariantTrait.php
+++ b/src/Rfc4122/VariantTrait.php
@@ -58,6 +58,12 @@ trait VariantTrait
throw new InvalidBytesException('Invalid number of bytes');
}
+ if ($this->isMax() || $this->isNil()) {
+ // RFC 4122 defines these special types of UUID, so we will consider
+ // them as belonging to the RFC 4122 variant.
+ return Uuid::RFC_4122;
+ }
+
/** @var array $parts */
$parts = unpack('n*', $this->getBytes());
diff --git a/src/Rfc4122/VersionTrait.php b/src/Rfc4122/VersionTrait.php
index b65ca7b..fb3e3e5 100644
--- a/src/Rfc4122/VersionTrait.php
+++ b/src/Rfc4122/VersionTrait.php
@@ -28,6 +28,11 @@ trait VersionTrait
*/
abstract public function getVersion(): ?int;
+ /**
+ * Returns true if these fields represent a max UUID
+ */
+ abstract public function isMax(): bool;
+
/**
* Returns true if these fields represent a nil UUID
*/
@@ -40,7 +45,7 @@ trait VersionTrait
*/
private function isCorrectVersion(): bool
{
- if ($this->isNil()) {
+ if ($this->isNil() || $this->isMax()) {
return true;
}
diff --git a/src/Uuid.php b/src/Uuid.php
index 0397de1..171d126 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -84,6 +84,14 @@ class Uuid implements UuidInterface
*/
public const NIL = '00000000-0000-0000-0000-000000000000';
+ /**
+ * The max UUID is a special form of UUID that is specified to have all 128
+ * bits set to one
+ *
+ * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4 Max UUID
+ */
+ public const MAX = 'ffffffff-ffff-ffff-ffff-ffffffffffff';
+
/**
* Variant: reserved, NCS backward compatibility
*
diff --git a/tests/ExpectedBehaviorTest.php b/tests/ExpectedBehaviorTest.php
index 82ae7eb..52a6d1e 100644
--- a/tests/ExpectedBehaviorTest.php
+++ b/tests/ExpectedBehaviorTest.php
@@ -198,6 +198,7 @@ class ExpectedBehaviorTest extends TestCase
// Non RFC 4122 UUIDs
['ffffffff-ffff-ffff-ffff-ffffffffffff', true],
+ ['00000000-0000-0000-0000-000000000000', true],
['ff6f8cb0-c57d-01e1-0b21-0800200c9a66', true],
['ff6f8cb0-c57d-01e1-1b21-0800200c9a66', true],
['ff6f8cb0-c57d-01e1-2b21-0800200c9a66', true],
@@ -254,7 +255,12 @@ class ExpectedBehaviorTest extends TestCase
$value = BigInteger::fromBase($value, 16)->__toString();
});
- $clockSeq = (int) $components[3] & 0x3fff;
+ if (strtolower($string) === Uuid::MAX) {
+ $clockSeq = (int) $components[3];
+ } else {
+ $clockSeq = (int) $components[3] & 0x3fff;
+ }
+
$clockSeqHiAndReserved = (int) $components[3] >> 8;
$clockSeqLow = (int) $components[3] & 0x00ff;
@@ -349,7 +355,7 @@ class ExpectedBehaviorTest extends TestCase
public function provideFromStringInteger()
{
return [
- ['00000000-0000-0000-0000-000000000000', null, 0, '0'],
+ ['00000000-0000-0000-0000-000000000000', null, 2, '0'],
['ff6f8cb0-c57d-11e1-8b21-0800200c9a66', 1, 2, '339532337419071774304650190139318639206'],
['ff6f8cb0-c57d-11e1-9b21-0800200c9a66', 1, 2, '339532337419071774305803111643925486182'],
['ff6f8cb0-c57d-11e1-ab21-0800200c9a66', 1, 2, '339532337419071774306956033148532333158'],
@@ -382,7 +388,7 @@ class ExpectedBehaviorTest extends TestCase
['ff6f8cb0-c57d-01e1-db21-0800200c9a66', null, 6, '339532337419071698752551071748029454950'],
['ff6f8cb0-c57d-01e1-eb21-0800200c9a66', null, 7, '339532337419071698753703993252636301926'],
['ff6f8cb0-c57d-01e1-fb21-0800200c9a66', null, 7, '339532337419071698754856914757243148902'],
- ['ffffffff-ffff-ffff-ffff-ffffffffffff', null, 7, '340282366920938463463374607431768211455'],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', null, 2, '340282366920938463463374607431768211455'],
];
}
@@ -641,6 +647,7 @@ class ExpectedBehaviorTest extends TestCase
['NAMESPACE_OID', '6ba7b812-9dad-11d1-80b4-00c04fd430c8'],
['NAMESPACE_X500', '6ba7b814-9dad-11d1-80b4-00c04fd430c8'],
['NIL', '00000000-0000-0000-0000-000000000000'],
+ ['MAX', 'ffffffff-ffff-ffff-ffff-ffffffffffff'],
['RESERVED_NCS', 0],
['RFC_4122', 2],
['RESERVED_MICROSOFT', 6],
@@ -651,6 +658,8 @@ class ExpectedBehaviorTest extends TestCase
['UUID_TYPE_HASH_MD5', 3],
['UUID_TYPE_RANDOM', 4],
['UUID_TYPE_HASH_SHA1', 5],
+ ['UUID_TYPE_REORDERED_TIME', 6],
+ ['UUID_TYPE_UNIX_TIME', 7],
];
}
}
diff --git a/tests/Guid/FieldsTest.php b/tests/Guid/FieldsTest.php
index d0f0689..f3bd810 100644
--- a/tests/Guid/FieldsTest.php
+++ b/tests/Guid/FieldsTest.php
@@ -139,6 +139,7 @@ class FieldsTest extends TestCase
['b08c6fff7dc5e111cb210800200c9a66', 'getVariant', 6],
['b08c6fff7dc5e111cb210800200c9a66', 'getVersion', 1],
['b08c6fff7dc5e111cb210800200c9a66', 'isNil', false],
+ ['b08c6fff7dc5e111cb210800200c9a66', 'isMax', false],
// For ff6f8cb0-c57d-41e1-db21-0800200c9a66
['b08c6fff7dc5e141db210800200c9a66', 'getClockSeq', '1b21'],
@@ -152,6 +153,7 @@ class FieldsTest extends TestCase
['b08c6fff7dc5e141db210800200c9a66', 'getVariant', 6],
['b08c6fff7dc5e141db210800200c9a66', 'getVersion', 4],
['b08c6fff7dc5e141db210800200c9a66', 'isNil', false],
+ ['b08c6fff7dc5e141db210800200c9a66', 'isMax', false],
// For ff6f8cb0-c57d-31e1-8b21-0800200c9a66
['b08c6fff7dc5e1318b210800200c9a66', 'getClockSeq', '0b21'],
@@ -165,6 +167,7 @@ class FieldsTest extends TestCase
['b08c6fff7dc5e1318b210800200c9a66', 'getVariant', 2],
['b08c6fff7dc5e1318b210800200c9a66', 'getVersion', 3],
['b08c6fff7dc5e1318b210800200c9a66', 'isNil', false],
+ ['b08c6fff7dc5e1318b210800200c9a66', 'isMax', false],
// For ff6f8cb0-c57d-51e1-9b21-0800200c9a66
['b08c6fff7dc5e1519b210800200c9a66', 'getClockSeq', '1b21'],
@@ -178,6 +181,7 @@ class FieldsTest extends TestCase
['b08c6fff7dc5e1519b210800200c9a66', 'getVariant', 2],
['b08c6fff7dc5e1519b210800200c9a66', 'getVersion', 5],
['b08c6fff7dc5e1519b210800200c9a66', 'isNil', false],
+ ['b08c6fff7dc5e1519b210800200c9a66', 'isMax', false],
// For 00000000-0000-0000-0000-000000000000
['00000000000000000000000000000000', 'getClockSeq', '0000'],
@@ -188,9 +192,24 @@ class FieldsTest extends TestCase
['00000000000000000000000000000000', 'getTimeLow', '00000000'],
['00000000000000000000000000000000', 'getTimeMid', '0000'],
['00000000000000000000000000000000', 'getTimestamp', '000000000000000'],
- ['00000000000000000000000000000000', 'getVariant', 0],
+ ['00000000000000000000000000000000', 'getVariant', 2],
['00000000000000000000000000000000', 'getVersion', null],
['00000000000000000000000000000000', 'isNil', true],
+ ['00000000000000000000000000000000', 'isMax', false],
+
+ // For ffffffff-ffff-ffff-ffff-ffffffffffff
+ ['ffffffffffffffffffffffffffffffff', 'getClockSeq', 'ffff'],
+ ['ffffffffffffffffffffffffffffffff', 'getClockSeqHiAndReserved', 'ff'],
+ ['ffffffffffffffffffffffffffffffff', 'getClockSeqLow', 'ff'],
+ ['ffffffffffffffffffffffffffffffff', 'getNode', 'ffffffffffff'],
+ ['ffffffffffffffffffffffffffffffff', 'getTimeHiAndVersion', 'ffff'],
+ ['ffffffffffffffffffffffffffffffff', 'getTimeLow', 'ffffffff'],
+ ['ffffffffffffffffffffffffffffffff', 'getTimeMid', 'ffff'],
+ ['ffffffffffffffffffffffffffffffff', 'getTimestamp', 'fffffffffffffff'],
+ ['ffffffffffffffffffffffffffffffff', 'getVariant', 2],
+ ['ffffffffffffffffffffffffffffffff', 'getVersion', null],
+ ['ffffffffffffffffffffffffffffffff', 'isNil', false],
+ ['ffffffffffffffffffffffffffffffff', 'isMax', true],
];
}
diff --git a/tests/Nonstandard/FieldsTest.php b/tests/Nonstandard/FieldsTest.php
index bb51fcc..b0be7ad 100644
--- a/tests/Nonstandard/FieldsTest.php
+++ b/tests/Nonstandard/FieldsTest.php
@@ -63,6 +63,7 @@ class FieldsTest extends TestCase
['ff6f8cb0-c57d-91e1-0b21-0800200c9a66', 'getVariant', Uuid::RESERVED_NCS],
['ff6f8cb0-c57d-91e1-0b21-0800200c9a66', 'getVersion', null],
['ff6f8cb0-c57d-91e1-0b21-0800200c9a66', 'isNil', false],
+ ['ff6f8cb0-c57d-91e1-0b21-0800200c9a66', 'isMax', false],
];
}
diff --git a/tests/Rfc4122/FieldsTest.php b/tests/Rfc4122/FieldsTest.php
index 97f7497..125575c 100644
--- a/tests/Rfc4122/FieldsTest.php
+++ b/tests/Rfc4122/FieldsTest.php
@@ -130,6 +130,7 @@ class FieldsTest extends TestCase
['ff6f8cb0-c57d-11e1-9b21-0800200c9a66', 'getVariant', 2],
['ff6f8cb0-c57d-11e1-9b21-0800200c9a66', 'getVersion', 1],
['ff6f8cb0-c57d-11e1-9b21-0800200c9a66', 'isNil', false],
+ ['ff6f8cb0-c57d-11e1-9b21-0800200c9a66', 'isMax', false],
['ff6f8cb0-c57d-41e1-ab21-0800200c9a66', 'getClockSeq', '2b21'],
['ff6f8cb0-c57d-41e1-ab21-0800200c9a66', 'getClockSeqHiAndReserved', 'ab'],
@@ -142,6 +143,7 @@ class FieldsTest extends TestCase
['ff6f8cb0-c57d-41e1-ab21-0800200c9a66', 'getVariant', 2],
['ff6f8cb0-c57d-41e1-ab21-0800200c9a66', 'getVersion', 4],
['ff6f8cb0-c57d-41e1-ab21-0800200c9a66', 'isNil', false],
+ ['ff6f8cb0-c57d-41e1-ab21-0800200c9a66', 'isMax', false],
['ff6f8cb0-c57d-31e1-bb21-0800200c9a66', 'getClockSeq', '3b21'],
['ff6f8cb0-c57d-31e1-bb21-0800200c9a66', 'getClockSeqHiAndReserved', 'bb'],
@@ -154,6 +156,7 @@ class FieldsTest extends TestCase
['ff6f8cb0-c57d-31e1-bb21-0800200c9a66', 'getVariant', 2],
['ff6f8cb0-c57d-31e1-bb21-0800200c9a66', 'getVersion', 3],
['ff6f8cb0-c57d-31e1-bb21-0800200c9a66', 'isNil', false],
+ ['ff6f8cb0-c57d-31e1-bb21-0800200c9a66', 'isMax', false],
['ff6f8cb0-c57d-51e1-8b21-0800200c9a66', 'getClockSeq', '0b21'],
['ff6f8cb0-c57d-51e1-8b21-0800200c9a66', 'getClockSeqHiAndReserved', '8b'],
@@ -166,6 +169,7 @@ class FieldsTest extends TestCase
['ff6f8cb0-c57d-51e1-8b21-0800200c9a66', 'getVariant', 2],
['ff6f8cb0-c57d-51e1-8b21-0800200c9a66', 'getVersion', 5],
['ff6f8cb0-c57d-51e1-8b21-0800200c9a66', 'isNil', false],
+ ['ff6f8cb0-c57d-51e1-8b21-0800200c9a66', 'isMax', false],
['ff6f8cb0-c57d-61e1-8b21-0800200c9a66', 'getClockSeq', '0b21'],
['ff6f8cb0-c57d-61e1-8b21-0800200c9a66', 'getClockSeqHiAndReserved', '8b'],
@@ -178,6 +182,7 @@ class FieldsTest extends TestCase
['ff6f8cb0-c57d-61e1-8b21-0800200c9a66', 'getVariant', 2],
['ff6f8cb0-c57d-61e1-8b21-0800200c9a66', 'getVersion', 6],
['ff6f8cb0-c57d-61e1-8b21-0800200c9a66', 'isNil', false],
+ ['ff6f8cb0-c57d-61e1-8b21-0800200c9a66', 'isMax', false],
['00000000-0000-0000-0000-000000000000', 'getClockSeq', '0000'],
['00000000-0000-0000-0000-000000000000', 'getClockSeqHiAndReserved', '00'],
@@ -187,9 +192,23 @@ class FieldsTest extends TestCase
['00000000-0000-0000-0000-000000000000', 'getTimeLow', '00000000'],
['00000000-0000-0000-0000-000000000000', 'getTimeMid', '0000'],
['00000000-0000-0000-0000-000000000000', 'getTimestamp', '000000000000000'],
- ['00000000-0000-0000-0000-000000000000', 'getVariant', 0],
+ ['00000000-0000-0000-0000-000000000000', 'getVariant', 2],
['00000000-0000-0000-0000-000000000000', 'getVersion', null],
['00000000-0000-0000-0000-000000000000', 'isNil', true],
+ ['00000000-0000-0000-0000-000000000000', 'isMax', false],
+
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getClockSeq', 'ffff'],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getClockSeqHiAndReserved', 'ff'],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getClockSeqLow', 'ff'],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getNode', 'ffffffffffff'],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getTimeHiAndVersion', 'ffff'],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getTimeLow', 'ffffffff'],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getTimeMid', 'ffff'],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getTimestamp', 'fffffffffffffff'],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getVariant', 2],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'getVersion', null],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'isNil', false],
+ ['ffffffff-ffff-ffff-ffff-ffffffffffff', 'isMax', true],
['000001f5-5cde-21ea-8400-0242ac130003', 'getClockSeq', '0400'],
['000001f5-5cde-21ea-8400-0242ac130003', 'getClockSeqHiAndReserved', '84'],
@@ -202,6 +221,7 @@ class FieldsTest extends TestCase
['000001f5-5cde-21ea-8400-0242ac130003', 'getVariant', 2],
['000001f5-5cde-21ea-8400-0242ac130003', 'getVersion', 2],
['000001f5-5cde-21ea-8400-0242ac130003', 'isNil', false],
+ ['000001f5-5cde-21ea-8400-0242ac130003', 'isMax', false],
['018339f0-1b83-71e1-9b21-0800200c9a66', 'getClockSeq', '1b21'],
['018339f0-1b83-71e1-9b21-0800200c9a66', 'getClockSeqHiAndReserved', '9b'],
@@ -214,6 +234,7 @@ class FieldsTest extends TestCase
['018339f0-1b83-71e1-9b21-0800200c9a66', 'getVariant', 2],
['018339f0-1b83-71e1-9b21-0800200c9a66', 'getVersion', 7],
['018339f0-1b83-71e1-9b21-0800200c9a66', 'isNil', false],
+ ['018339f0-1b83-71e1-9b21-0800200c9a66', 'isMax', false],
];
}
diff --git a/tests/Rfc4122/UuidBuilderTest.php b/tests/Rfc4122/UuidBuilderTest.php
index bf8a816..07f2d07 100644
--- a/tests/Rfc4122/UuidBuilderTest.php
+++ b/tests/Rfc4122/UuidBuilderTest.php
@@ -13,6 +13,8 @@ use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Nonstandard\UuidV6 as NonstandardUuidV6;
use Ramsey\Uuid\Rfc4122\Fields;
use Ramsey\Uuid\Rfc4122\FieldsInterface;
+use Ramsey\Uuid\Rfc4122\MaxUuid;
+use Ramsey\Uuid\Rfc4122\NilUuid;
use Ramsey\Uuid\Rfc4122\UuidBuilder;
use Ramsey\Uuid\Rfc4122\UuidV1;
use Ramsey\Uuid\Rfc4122\UuidV2;
@@ -33,7 +35,7 @@ class UuidBuilderTest extends TestCase
*
* @dataProvider provideBuildTestValues
*/
- public function testBuild(string $uuid, string $expectedClass, int $expectedVersion): void
+ public function testBuild(string $uuid, string $expectedClass, ?int $expectedVersion): void
{
$bytes = (string) hex2bin(str_replace('-', '', $uuid));
@@ -58,6 +60,16 @@ class UuidBuilderTest extends TestCase
public function provideBuildTestValues(): array
{
return [
+ [
+ 'uuid' => '00000000-0000-0000-0000-000000000000',
+ 'expectedClass' => NilUuid::class,
+ 'expectedVersion' => null,
+ ],
+ [
+ 'uuid' => 'ffffffff-ffff-ffff-ffff-ffffffffffff',
+ 'expectedClass' => MaxUuid::class,
+ 'expectedVersion' => null,
+ ],
[
'uuid' => 'ff6f8cb0-c57d-11e1-9b21-0800200c9a66',
'expectedClass' => UuidV1::class,
@@ -127,6 +139,7 @@ class UuidBuilderTest extends TestCase
{
$fields = Mockery::mock(FieldsInterface::class, [
'isNil' => false,
+ 'isMax' => false,
'getVersion' => 255,
]);
diff --git a/tests/Rfc4122/VariantTraitTest.php b/tests/Rfc4122/VariantTraitTest.php
index c0e2593..8883624 100644
--- a/tests/Rfc4122/VariantTraitTest.php
+++ b/tests/Rfc4122/VariantTraitTest.php
@@ -23,6 +23,8 @@ class VariantTraitTest extends TestCase
/** @var Fields $trait */
$trait = Mockery::mock(VariantTrait::class, [
'getBytes' => $bytes,
+ 'isMax' => false,
+ 'isNil' => false,
]);
$this->expectException(InvalidBytesException::class);
@@ -52,6 +54,8 @@ class VariantTraitTest extends TestCase
/** @var Fields $trait */
$trait = Mockery::mock(VariantTrait::class, [
'getBytes' => $bytes,
+ 'isMax' => false,
+ 'isNil' => false,
]);
$this->assertSame($expectedVariant, $trait->getVariant());
diff --git a/tests/UuidTest.php b/tests/UuidTest.php
index 5f71905..06dbb4d 100644
--- a/tests/UuidTest.php
+++ b/tests/UuidTest.php
@@ -29,6 +29,7 @@ use Ramsey\Uuid\Guid\Guid;
use Ramsey\Uuid\Lazy\LazyUuidFromString;
use Ramsey\Uuid\Provider\Node\RandomNodeProvider;
use Ramsey\Uuid\Provider\Time\FixedTimeProvider;
+use Ramsey\Uuid\Rfc4122\Fields;
use Ramsey\Uuid\Rfc4122\FieldsInterface;
use Ramsey\Uuid\Rfc4122\UuidV1;
use Ramsey\Uuid\Type\Hexadecimal;
@@ -146,6 +147,30 @@ class UuidTest extends TestCase
$this->assertInstanceOf(LazyUuidFromString::class, Uuid::fromString('FF6F8CB0-C57D-11E1-9B21-0800200C9A66'));
}
+ public function testFromStringWithNilUuid(): void
+ {
+ $uuid = Uuid::fromString(Uuid::NIL);
+
+ /** @var Fields $fields */
+ $fields = $uuid->getFields();
+
+ $this->assertSame('00000000-0000-0000-0000-000000000000', $uuid->toString());
+ $this->assertTrue($fields->isNil());
+ $this->assertFalse($fields->isMax());
+ }
+
+ public function testFromStringWithMaxUuid(): void
+ {
+ $uuid = Uuid::fromString(Uuid::MAX);
+
+ /** @var Fields $fields */
+ $fields = $uuid->getFields();
+
+ $this->assertSame('ffffffff-ffff-ffff-ffff-ffffffffffff', $uuid->toString());
+ $this->assertFalse($fields->isNil());
+ $this->assertTrue($fields->isMax());
+ }
+
public function testGetBytes(): void
{
$uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66');
@@ -1297,7 +1322,13 @@ class UuidTest extends TestCase
'urn' => 'urn:uuid:00000000-0000-0000-0000-000000000000',
'time' => '0',
'clock_seq' => '0000',
- 'variant' => Uuid::RESERVED_NCS,
+ // This is a departure from the Python tests. The Python tests
+ // are technically "correct" because all bits are set to zero,
+ // so it stands to reason that the variant is also zero, but
+ // that leads to this being considered a "Reserved NCS" variant,
+ // and that is not the case. RFC 4122 defines this special UUID,
+ // so it is an RFC 4122 variant.
+ 'variant' => Uuid::RFC_4122,
'version' => null,
],
[
@@ -1556,8 +1587,20 @@ class UuidTest extends TestCase
],
'urn' => 'urn:uuid:ffffffff-ffff-ffff-ffff-ffffffffffff',
'time' => 'fffffffffffffff',
- 'clock_seq' => '3fff',
- 'variant' => Uuid::RESERVED_FUTURE,
+ // This is a departure from the Python tests. The Python tests
+ // are technically "correct" because all bits are set to one,
+ // which ends up calculating the variant as 7, or "Reserved
+ // Future," but that is not the case, and now that max UUIDs
+ // are defined as a special type, within the RFC 4122 variant
+ // rules, we also consider it an RFC 4122 variant.
+ //
+ // Similarly, Python's tests think the clock sequence should be
+ // 0x3fff because of the bit shifting performed on this field.
+ // However, since all the bits in this UUID are defined as being
+ // set to one, we will consider the clock sequence as 0xffff,
+ // which all bits set to one.
+ 'clock_seq' => 'ffff',
+ 'variant' => Uuid::RFC_4122,
'version' => null,
],
];
diff --git a/tests/benchmark/UuidGenerationBench.php b/tests/benchmark/UuidGenerationBench.php
index c3838e1..b474993 100644
--- a/tests/benchmark/UuidGenerationBench.php
+++ b/tests/benchmark/UuidGenerationBench.php
@@ -14,6 +14,7 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Benchmark;
+use DateTimeImmutable;
use Ramsey\Uuid\Provider\Node\StaticNodeProvider;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerIdentifier;
@@ -104,4 +105,9 @@ final class UuidGenerationBench
{
Uuid::uuid7();
}
+
+ public function benchUuid7GenerationWithDateTime(): void
+ {
+ Uuid::uuid7(new DateTimeImmutable('@1663203901.667000'));
+ }
}
From ef842484ba57f163c6d465ab744bfecb872a11d4 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Wed, 14 Sep 2022 20:44:53 -0500
Subject: [PATCH 43/74] chore: prepare for release 4.5.0
---
CHANGELOG.md | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5b2aad5..3086d5a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,47 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## 4.5.0 - 2022-09-15
+
+### Added
+
+* Promote version 6, reordered time UUIDs from the `Nonstandard` namespace to
+ the `Rfc4122` namespace. Version 6 UUIDs are defined in
+ [New UUID Formats, section 5.1][version6]. While still an Internet-Draft
+ version 6 is stable and unlikely to change in any way that breaks compatibility.
+* Add support for version 7, Unix Epoch time UUIDs, as defined in
+ [New UUID Formats, section 5.2][version7]. While still an Internet-Draft,
+ version 7 is stable and unlikely to change in any way that breaks compatibility.
+ * Use `Ramsey\Uuid\Uuid::uuid7()` to generate version 7 UUIDs.
+ * Version 7 UUIDs are of type `Ramsey\Uuid\Rfc4122\UuidV7`.
+ * The constant `Ramsey\Uuid\Uuid::UUID_TYPE_UNIX_TIME` exists for version
+ 7 UUIDs.
+* Add `Ramsey\Uuid\Converter\Time\UnixTimeConverter` and
+ `Ramsey\Uuid\Generator\UnixTimeGenerator` to support version 7 UUID generation.
+* Add support for [max UUIDs][] through `Ramsey\Uuid\Uuid::MAX` and
+ `Ramsey\Uuid\Rfc4122\MaxUuid`.
+
+### Changed
+
+* The lowest version of brick/math allowed is now `^0.8.8`.
+
+### Deprecated
+
+The following will be removed in ramsey/uuid 5.0.0:
+
+* `Ramsey\Uuid\Nonstandard\UuidV6` is deprecated in favor of
+ `Ramsey\Uuid\Rfc4122\UuidV6`.
+* `Ramsey\Uuid\Uuid::UUID_TYPE_PEABODY`; use
+ `Ramsey\Uuid\Uuid::UUID_TYPE_REORDERED_TIME` instead.
+
+### Fixed
+
+* For `Ramsey\Uuid\Uuid::isValid()`, Psalm now asserts the UUID is a
+ non-empty-string when it is valid.
+* Nil UUIDs are properly treated as RFC 4122 variants, and `getVariant()` now
+ returns a `2` when called on a nil UUID.
+
+
## 4.4.0 - 2022-08-05
### Changed
@@ -1315,3 +1356,6 @@ versions leading up to this release.*
[doctrine field type]: http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html
[ramsey/uuid-doctrine]: https://github.com/ramsey/uuid-doctrine
[ramsey/uuid-console]: https://github.com/ramsey/uuid-console
+[version6]: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1
+[version7]: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2
+[max uuids]: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4
From ae247f1dcd5b73ffe1882d9c135f79738386e731 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 15 Sep 2022 22:14:04 -0500
Subject: [PATCH 44/74] chore: clean up types and PHP 8-ify the code
---
phpstan.neon.dist | 2 +-
src/Builder/DegradedUuidBuilder.php | 13 +--
src/Builder/FallbackBuilder.php | 8 +-
src/Codec/StringCodec.php | 8 +-
src/Converter/Number/BigNumberConverter.php | 5 +-
.../Number/GenericNumberConverter.php | 8 +-
src/Converter/Time/BigNumberTimeConverter.php | 5 +-
src/Converter/Time/GenericTimeConverter.php | 8 +-
src/Converter/Time/PhpTimeConverter.php | 21 +---
src/Converter/Time/UnixTimeConverter.php | 5 +-
src/FeatureSet.php | 108 +++---------------
src/Fields/SerializableFieldsTrait.php | 13 ++-
src/Generator/CombGenerator.php | 20 +---
src/Generator/DceSecurityGenerator.php | 27 +----
src/Generator/DefaultTimeGenerator.php | 28 +----
src/Generator/PeclUuidNameGenerator.php | 21 ++--
src/Generator/RandomLibAdapter.php | 5 +-
src/Generator/TimeGeneratorFactory.php | 24 +---
src/Generator/UnixTimeGenerator.php | 13 +--
src/Guid/Fields.php | 13 +--
src/Guid/GuidBuilder.php | 16 +--
src/Lazy/LazyUuidFromString.php | 25 ++--
src/Nonstandard/Fields.php | 13 +--
src/Nonstandard/UuidBuilder.php | 16 +--
.../Dce/SystemDceSecurityProvider.php | 29 ++---
src/Provider/Node/FallbackNodeProvider.php | 10 +-
src/Provider/Node/StaticNodeProvider.php | 5 +-
src/Provider/Time/FixedTimeProvider.php | 14 +--
src/Rfc4122/Fields.php | 83 ++++++--------
src/Rfc4122/UuidBuilder.php | 8 +-
src/Rfc4122/VariantTrait.php | 18 ++-
src/Rfc4122/VersionTrait.php | 19 ++-
src/Type/Decimal.php | 25 ++--
src/Type/Hexadecimal.php | 16 +--
src/Type/Integer.php | 19 +--
src/Type/Time.php | 28 ++---
src/Uuid.php | 49 +++-----
src/UuidFactory.php | 79 ++++---------
tests/Generator/RandomLibAdapterTest.php | 6 +-
39 files changed, 225 insertions(+), 608 deletions(-)
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index d31b470..46766b1 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -17,7 +17,7 @@ parameters:
count: 9
path: ./src/Lazy/LazyUuidFromString.php
-
- message: '#^Property Ramsey\\Uuid\\FeatureSet::\$disableBigNumber is never read, only written#'
+ message: '#^Constructor of class Ramsey\\Uuid\\FeatureSet has an unused parameter \$forceNoBigNumber\.#'
count: 1
path: ./src/FeatureSet.php
diff --git a/src/Builder/DegradedUuidBuilder.php b/src/Builder/DegradedUuidBuilder.php
index 23931e4..20b3842 100644
--- a/src/Builder/DegradedUuidBuilder.php
+++ b/src/Builder/DegradedUuidBuilder.php
@@ -30,15 +30,7 @@ use Ramsey\Uuid\UuidInterface;
*/
class DegradedUuidBuilder implements UuidBuilderInterface
{
- /**
- * @var NumberConverterInterface
- */
- private $numberConverter;
-
- /**
- * @var TimeConverterInterface
- */
- private $timeConverter;
+ private TimeConverterInterface $timeConverter;
/**
* @param NumberConverterInterface $numberConverter The number converter to
@@ -47,10 +39,9 @@ class DegradedUuidBuilder implements UuidBuilderInterface
* for converting timestamps extracted from a UUID to Unix timestamps
*/
public function __construct(
- NumberConverterInterface $numberConverter,
+ private NumberConverterInterface $numberConverter,
?TimeConverterInterface $timeConverter = null
) {
- $this->numberConverter = $numberConverter;
$this->timeConverter = $timeConverter ?: new DegradedTimeConverter();
}
diff --git a/src/Builder/FallbackBuilder.php b/src/Builder/FallbackBuilder.php
index 8ab438a..ba5f31f 100644
--- a/src/Builder/FallbackBuilder.php
+++ b/src/Builder/FallbackBuilder.php
@@ -27,17 +27,11 @@ use Ramsey\Uuid\UuidInterface;
*/
class FallbackBuilder implements UuidBuilderInterface
{
- /**
- * @var iterable
- */
- private $builders;
-
/**
* @param iterable $builders An array of UUID builders
*/
- public function __construct(iterable $builders)
+ public function __construct(private iterable $builders)
{
- $this->builders = $builders;
}
/**
diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php
index 58c9f58..4b6e4e5 100644
--- a/src/Codec/StringCodec.php
+++ b/src/Codec/StringCodec.php
@@ -36,19 +36,13 @@ use function substr;
*/
class StringCodec implements CodecInterface
{
- /**
- * @var UuidBuilderInterface
- */
- private $builder;
-
/**
* Constructs a StringCodec
*
* @param UuidBuilderInterface $builder The builder to use when encoding UUIDs
*/
- public function __construct(UuidBuilderInterface $builder)
+ public function __construct(private UuidBuilderInterface $builder)
{
- $this->builder = $builder;
}
public function encode(UuidInterface $uuid): string
diff --git a/src/Converter/Number/BigNumberConverter.php b/src/Converter/Number/BigNumberConverter.php
index fef63fd..99b88b3 100644
--- a/src/Converter/Number/BigNumberConverter.php
+++ b/src/Converter/Number/BigNumberConverter.php
@@ -27,10 +27,7 @@ use Ramsey\Uuid\Math\BrickMathCalculator;
*/
class BigNumberConverter implements NumberConverterInterface
{
- /**
- * @var NumberConverterInterface
- */
- private $converter;
+ private NumberConverterInterface $converter;
public function __construct()
{
diff --git a/src/Converter/Number/GenericNumberConverter.php b/src/Converter/Number/GenericNumberConverter.php
index 501eac0..043c3c4 100644
--- a/src/Converter/Number/GenericNumberConverter.php
+++ b/src/Converter/Number/GenericNumberConverter.php
@@ -26,14 +26,8 @@ use Ramsey\Uuid\Type\Integer as IntegerObject;
*/
class GenericNumberConverter implements NumberConverterInterface
{
- /**
- * @var CalculatorInterface
- */
- private $calculator;
-
- public function __construct(CalculatorInterface $calculator)
+ public function __construct(private CalculatorInterface $calculator)
{
- $this->calculator = $calculator;
}
/**
diff --git a/src/Converter/Time/BigNumberTimeConverter.php b/src/Converter/Time/BigNumberTimeConverter.php
index 7390dad..b6bca9e 100644
--- a/src/Converter/Time/BigNumberTimeConverter.php
+++ b/src/Converter/Time/BigNumberTimeConverter.php
@@ -29,10 +29,7 @@ use Ramsey\Uuid\Type\Time;
*/
class BigNumberTimeConverter implements TimeConverterInterface
{
- /**
- * @var TimeConverterInterface
- */
- private $converter;
+ private TimeConverterInterface $converter;
public function __construct()
{
diff --git a/src/Converter/Time/GenericTimeConverter.php b/src/Converter/Time/GenericTimeConverter.php
index a8aa64b..f6b60ab 100644
--- a/src/Converter/Time/GenericTimeConverter.php
+++ b/src/Converter/Time/GenericTimeConverter.php
@@ -50,14 +50,8 @@ class GenericTimeConverter implements TimeConverterInterface
*/
private const MICROSECOND_INTERVALS = '10';
- /**
- * @var CalculatorInterface
- */
- private $calculator;
-
- public function __construct(CalculatorInterface $calculator)
+ public function __construct(private CalculatorInterface $calculator)
{
- $this->calculator = $calculator;
}
public function calculateTime(string $seconds, string $microseconds): Hexadecimal
diff --git a/src/Converter/Time/PhpTimeConverter.php b/src/Converter/Time/PhpTimeConverter.php
index 538d2f2..66009f1 100644
--- a/src/Converter/Time/PhpTimeConverter.php
+++ b/src/Converter/Time/PhpTimeConverter.php
@@ -58,20 +58,9 @@ class PhpTimeConverter implements TimeConverterInterface
*/
private const MICROSECOND_INTERVALS = 10;
- /**
- * @var CalculatorInterface
- */
- private $calculator;
-
- /**
- * @var TimeConverterInterface
- */
- private $fallbackConverter;
-
- /**
- * @var int
- */
- private $phpPrecision;
+ private int $phpPrecision;
+ private CalculatorInterface $calculator;
+ private TimeConverterInterface $fallbackConverter;
public function __construct(
?CalculatorInterface $calculator = null,
@@ -132,11 +121,11 @@ class PhpTimeConverter implements TimeConverterInterface
}
/**
- * @param int|float $time The time to split into seconds and microseconds
+ * @param float|int $time The time to split into seconds and microseconds
*
* @return string[]
*/
- private function splitTime($time): array
+ private function splitTime(float | int $time): array
{
$split = explode('.', (string) $time, 2);
diff --git a/src/Converter/Time/UnixTimeConverter.php b/src/Converter/Time/UnixTimeConverter.php
index d94233f..4d6d0a8 100644
--- a/src/Converter/Time/UnixTimeConverter.php
+++ b/src/Converter/Time/UnixTimeConverter.php
@@ -36,11 +36,8 @@ class UnixTimeConverter implements TimeConverterInterface
{
private const MILLISECONDS = 1000;
- private CalculatorInterface $calculator;
-
- public function __construct(CalculatorInterface $calculator)
+ public function __construct(private CalculatorInterface $calculator)
{
- $this->calculator = $calculator;
}
public function calculateTime(string $seconds, string $microseconds): Hexadecimal
diff --git a/src/FeatureSet.php b/src/FeatureSet.php
index 482a8de..6c8ccb0 100644
--- a/src/FeatureSet.php
+++ b/src/FeatureSet.php
@@ -63,94 +63,25 @@ use const PHP_INT_SIZE;
*/
class FeatureSet
{
- /**
- * @var bool
- */
- private $disableBigNumber = false;
-
- /**
- * @var bool
- */
- private $disable64Bit = false;
-
- /**
- * @var bool
- */
- private $ignoreSystemNode = false;
-
- /**
- * @var bool
- */
- private $enablePecl = false;
-
- /**
- * @var UuidBuilderInterface
- */
- private $builder;
-
- /**
- * @var CodecInterface
- */
- private $codec;
-
- /**
- * @var DceSecurityGeneratorInterface
- */
- private $dceSecurityGenerator;
-
- /**
- * @var NameGeneratorInterface
- */
- private $nameGenerator;
-
- /**
- * @var NodeProviderInterface
- */
- private $nodeProvider;
-
- /**
- * @var NumberConverterInterface
- */
- private $numberConverter;
-
- /**
- * @var TimeConverterInterface
- */
- private $timeConverter;
-
- /**
- * @var RandomGeneratorInterface
- */
- private $randomGenerator;
-
- /**
- * @var TimeGeneratorInterface
- */
- private $timeGenerator;
-
- /**
- * @var TimeProviderInterface|null
- */
- private $timeProvider;
-
- /**
- * @var ValidatorInterface
- */
- private $validator;
-
- /**
- * @var CalculatorInterface
- */
- private $calculator;
-
+ private ?TimeProviderInterface $timeProvider = null;
+ private CalculatorInterface $calculator;
+ 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 $builder;
+ private ValidatorInterface $validator;
/**
* @param bool $useGuids True build UUIDs using the GuidStringCodec
* @param bool $force32Bit True to force the use of 32-bit functionality
* (primarily for testing purposes)
- * @param bool $forceNoBigNumber True to disable the use of moontoast/math
- * (primarily for testing purposes)
+ * @param bool $forceNoBigNumber (obsolete)
* @param bool $ignoreSystemNode True to disable attempts to check for the
* system node ID (primarily for testing purposes)
* @param bool $enablePecl True to enable the use of the PeclUuidTimeGenerator
@@ -158,16 +89,11 @@ class FeatureSet
*/
public function __construct(
bool $useGuids = false,
- bool $force32Bit = false,
+ private bool $force32Bit = false,
bool $forceNoBigNumber = false,
- bool $ignoreSystemNode = false,
- bool $enablePecl = false
+ private bool $ignoreSystemNode = false,
+ private bool $enablePecl = false
) {
- $this->disableBigNumber = $forceNoBigNumber;
- $this->disable64Bit = $force32Bit;
- $this->ignoreSystemNode = $ignoreSystemNode;
- $this->enablePecl = $enablePecl;
-
$this->randomGenerator = $this->buildRandomGenerator();
$this->setCalculator(new BrickMathCalculator());
$this->builder = $this->buildUuidBuilder($useGuids);
@@ -474,6 +400,6 @@ class FeatureSet
*/
private function is64BitSystem(): bool
{
- return PHP_INT_SIZE === 8 && !$this->disable64Bit;
+ return PHP_INT_SIZE === 8 && !$this->force32Bit;
}
}
diff --git a/src/Fields/SerializableFieldsTrait.php b/src/Fields/SerializableFieldsTrait.php
index a2a89c6..3d36b6f 100644
--- a/src/Fields/SerializableFieldsTrait.php
+++ b/src/Fields/SerializableFieldsTrait.php
@@ -56,22 +56,23 @@ trait SerializableFieldsTrait
/**
* Constructs the object from a serialized string representation
*
- * @param string $serialized The serialized string representation of the object
+ * @param string $data The serialized string representation of the object
*
- * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
- public function unserialize($serialized): void
+ public function unserialize(string $data): void
{
- if (strlen($serialized) === 16) {
- $this->__construct($serialized);
+ if (strlen($data) === 16) {
+ $this->__construct($data);
} else {
- $this->__construct(base64_decode($serialized));
+ $this->__construct(base64_decode($data));
}
}
/**
* @param array{bytes?: string} $data
+ *
+ * @psalm-suppress UnusedMethodCall
*/
public function __unserialize(array $data): void
{
diff --git a/src/Generator/CombGenerator.php b/src/Generator/CombGenerator.php
index 25b7988..0e88706 100644
--- a/src/Generator/CombGenerator.php
+++ b/src/Generator/CombGenerator.php
@@ -61,22 +61,10 @@ class CombGenerator implements RandomGeneratorInterface
{
public const TIMESTAMP_BYTES = 6;
- /**
- * @var RandomGeneratorInterface
- */
- private $randomGenerator;
-
- /**
- * @var NumberConverterInterface
- */
- private $converter;
-
public function __construct(
- RandomGeneratorInterface $generator,
- NumberConverterInterface $numberConverter
+ private RandomGeneratorInterface $generator,
+ private NumberConverterInterface $numberConverter
) {
- $this->converter = $numberConverter;
- $this->randomGenerator = $generator;
}
/**
@@ -95,11 +83,11 @@ class CombGenerator implements RandomGeneratorInterface
$hash = '';
if (self::TIMESTAMP_BYTES > 0 && $length > self::TIMESTAMP_BYTES) {
- $hash = $this->randomGenerator->generate($length - self::TIMESTAMP_BYTES);
+ $hash = $this->generator->generate($length - self::TIMESTAMP_BYTES);
}
$lsbTime = str_pad(
- $this->converter->toHex($this->timestamp()),
+ $this->numberConverter->toHex($this->timestamp()),
self::TIMESTAMP_BYTES * 2,
'0',
STR_PAD_LEFT
diff --git a/src/Generator/DceSecurityGenerator.php b/src/Generator/DceSecurityGenerator.php
index aca8c5d..37ba781 100644
--- a/src/Generator/DceSecurityGenerator.php
+++ b/src/Generator/DceSecurityGenerator.php
@@ -52,29 +52,11 @@ class DceSecurityGenerator implements DceSecurityGeneratorInterface
*/
private const CLOCK_SEQ_LOW = 0;
- /**
- * @var NumberConverterInterface
- */
- private $numberConverter;
-
- /**
- * @var TimeGeneratorInterface
- */
- private $timeGenerator;
-
- /**
- * @var DceSecurityProviderInterface
- */
- private $dceSecurityProvider;
-
public function __construct(
- NumberConverterInterface $numberConverter,
- TimeGeneratorInterface $timeGenerator,
- DceSecurityProviderInterface $dceSecurityProvider
+ private NumberConverterInterface $numberConverter,
+ private TimeGeneratorInterface $timeGenerator,
+ private DceSecurityProviderInterface $dceSecurityProvider
) {
- $this->numberConverter = $numberConverter;
- $this->timeGenerator = $timeGenerator;
- $this->dceSecurityProvider = $dceSecurityProvider;
}
public function generate(
@@ -153,8 +135,7 @@ class DceSecurityGenerator implements DceSecurityGeneratorInterface
// Replace bytes in the time-based UUID with DCE Security values.
$bytes = substr_replace($bytes, $identifierBytes, 0, 4);
- $bytes = substr_replace($bytes, $domainByte, 9, 1);
- return $bytes;
+ return substr_replace($bytes, $domainByte, 9, 1);
}
}
diff --git a/src/Generator/DefaultTimeGenerator.php b/src/Generator/DefaultTimeGenerator.php
index d245c7b..a1b39b0 100644
--- a/src/Generator/DefaultTimeGenerator.php
+++ b/src/Generator/DefaultTimeGenerator.php
@@ -40,29 +40,11 @@ use const STR_PAD_LEFT;
*/
class DefaultTimeGenerator implements TimeGeneratorInterface
{
- /**
- * @var NodeProviderInterface
- */
- private $nodeProvider;
-
- /**
- * @var TimeConverterInterface
- */
- private $timeConverter;
-
- /**
- * @var TimeProviderInterface
- */
- private $timeProvider;
-
public function __construct(
- NodeProviderInterface $nodeProvider,
- TimeConverterInterface $timeConverter,
- TimeProviderInterface $timeProvider
+ private NodeProviderInterface $nodeProvider,
+ private TimeConverterInterface $timeConverter,
+ private TimeProviderInterface $timeProvider
) {
- $this->nodeProvider = $nodeProvider;
- $this->timeConverter = $timeConverter;
- $this->timeProvider = $timeProvider;
}
/**
@@ -121,13 +103,13 @@ class DefaultTimeGenerator implements TimeGeneratorInterface
* Uses the node provider given when constructing this instance to get
* the node ID (usually a MAC address)
*
- * @param string|int|null $node A node value that may be used to override the node provider
+ * @param int|string|null $node A node value that may be used to override the node provider
*
* @return string 6-byte binary string representation of the node
*
* @throws InvalidArgumentException
*/
- private function getValidNode($node): string
+ private function getValidNode(int | string | null $node): string
{
if ($node === null) {
$node = $this->nodeProvider->getNode();
diff --git a/src/Generator/PeclUuidNameGenerator.php b/src/Generator/PeclUuidNameGenerator.php
index 3780c5c..6a6d1ae 100644
--- a/src/Generator/PeclUuidNameGenerator.php
+++ b/src/Generator/PeclUuidNameGenerator.php
@@ -33,21 +33,16 @@ class PeclUuidNameGenerator implements NameGeneratorInterface
/** @psalm-pure */
public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string
{
- switch ($hashAlgorithm) {
- case 'md5':
- $uuid = uuid_generate_md5($ns->toString(), $name);
-
- break;
- case 'sha1':
- $uuid = uuid_generate_sha1($ns->toString(), $name);
-
- break;
- default:
- throw new NameException(sprintf(
+ $uuid = match ($hashAlgorithm) {
+ 'md5' => uuid_generate_md5($ns->toString(), $name),
+ 'sha1' => uuid_generate_sha1($ns->toString(), $name),
+ default => throw new NameException(
+ sprintf(
'Unable to hash namespace and name with algorithm \'%s\'',
$hashAlgorithm
- ));
- }
+ )
+ ),
+ };
return uuid_parse($uuid);
}
diff --git a/src/Generator/RandomLibAdapter.php b/src/Generator/RandomLibAdapter.php
index 793ccd5..fd0ccc8 100644
--- a/src/Generator/RandomLibAdapter.php
+++ b/src/Generator/RandomLibAdapter.php
@@ -29,10 +29,7 @@ use RandomLib\Generator;
*/
class RandomLibAdapter implements RandomGeneratorInterface
{
- /**
- * @var Generator
- */
- private $generator;
+ private Generator $generator;
/**
* Constructs a RandomLibAdapter
diff --git a/src/Generator/TimeGeneratorFactory.php b/src/Generator/TimeGeneratorFactory.php
index 3d55fc4..8d06fc3 100644
--- a/src/Generator/TimeGeneratorFactory.php
+++ b/src/Generator/TimeGeneratorFactory.php
@@ -24,29 +24,11 @@ use Ramsey\Uuid\Provider\TimeProviderInterface;
*/
class TimeGeneratorFactory
{
- /**
- * @var NodeProviderInterface
- */
- private $nodeProvider;
-
- /**
- * @var TimeConverterInterface
- */
- private $timeConverter;
-
- /**
- * @var TimeProviderInterface
- */
- private $timeProvider;
-
public function __construct(
- NodeProviderInterface $nodeProvider,
- TimeConverterInterface $timeConverter,
- TimeProviderInterface $timeProvider
+ private NodeProviderInterface $nodeProvider,
+ private TimeConverterInterface $timeConverter,
+ private TimeProviderInterface $timeProvider
) {
- $this->nodeProvider = $nodeProvider;
- $this->timeConverter = $timeConverter;
- $this->timeProvider = $timeProvider;
}
/**
diff --git a/src/Generator/UnixTimeGenerator.php b/src/Generator/UnixTimeGenerator.php
index 74914dd..1aef869 100644
--- a/src/Generator/UnixTimeGenerator.php
+++ b/src/Generator/UnixTimeGenerator.php
@@ -25,18 +25,11 @@ use function hex2bin;
*/
class UnixTimeGenerator implements TimeGeneratorInterface
{
- private RandomGeneratorInterface $randomGenerator;
- private TimeConverterInterface $timeConverter;
- private TimeProviderInterface $timeProvider;
-
public function __construct(
- TimeConverterInterface $timeConverter,
- TimeProviderInterface $timeProvider,
- RandomGeneratorInterface $randomGenerator
+ private TimeConverterInterface $timeConverter,
+ private TimeProviderInterface $timeProvider,
+ private RandomGeneratorInterface $randomGenerator
) {
- $this->timeConverter = $timeConverter;
- $this->timeProvider = $timeProvider;
- $this->randomGenerator = $randomGenerator;
}
/**
diff --git a/src/Guid/Fields.php b/src/Guid/Fields.php
index 9e47aff..0fc5d1c 100644
--- a/src/Guid/Fields.php
+++ b/src/Guid/Fields.php
@@ -51,11 +51,6 @@ final class Fields implements FieldsInterface
use VariantTrait;
use VersionTrait;
- /**
- * @var string
- */
- private $bytes;
-
/**
* @param string $bytes A 16-byte binary string representation of a UUID
*
@@ -63,17 +58,15 @@ final class Fields implements FieldsInterface
* @throws InvalidArgumentException if the byte string does not represent a GUID
* @throws InvalidArgumentException if the byte string does not contain a valid version
*/
- public function __construct(string $bytes)
+ public function __construct(private string $bytes)
{
- if (strlen($bytes) !== 16) {
+ if (strlen($this->bytes) !== 16) {
throw new InvalidArgumentException(
'The byte string must be 16 bytes long; '
- . 'received ' . strlen($bytes) . ' bytes'
+ . 'received ' . strlen($this->bytes) . ' bytes'
);
}
- $this->bytes = $bytes;
-
if (!$this->isCorrectVariant()) {
throw new InvalidArgumentException(
'The byte string received does not conform to the RFC '
diff --git a/src/Guid/GuidBuilder.php b/src/Guid/GuidBuilder.php
index 758dd6b..c036bb2 100644
--- a/src/Guid/GuidBuilder.php
+++ b/src/Guid/GuidBuilder.php
@@ -31,16 +31,6 @@ use Throwable;
*/
class GuidBuilder implements UuidBuilderInterface
{
- /**
- * @var NumberConverterInterface
- */
- private $numberConverter;
-
- /**
- * @var TimeConverterInterface
- */
- private $timeConverter;
-
/**
* @param NumberConverterInterface $numberConverter The number converter to
* use when constructing the Guid
@@ -48,11 +38,9 @@ class GuidBuilder implements UuidBuilderInterface
* for converting timestamps extracted from a UUID to Unix timestamps
*/
public function __construct(
- NumberConverterInterface $numberConverter,
- TimeConverterInterface $timeConverter
+ private NumberConverterInterface $numberConverter,
+ private TimeConverterInterface $timeConverter
) {
- $this->numberConverter = $numberConverter;
- $this->timeConverter = $timeConverter;
}
/**
diff --git a/src/Lazy/LazyUuidFromString.php b/src/Lazy/LazyUuidFromString.php
index d2a169f..c0b47bb 100644
--- a/src/Lazy/LazyUuidFromString.php
+++ b/src/Lazy/LazyUuidFromString.php
@@ -55,18 +55,14 @@ use function substr;
final class LazyUuidFromString implements UuidInterface
{
public const VALID_REGEX = '/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/ms';
- /**
- * @var string
- * @psalm-var non-empty-string
- */
- private $uuid;
- /** @var UuidInterface|null */
- private $unwrapped;
- /** @psalm-param non-empty-string $uuid */
- public function __construct(string $uuid)
+ private ?UuidInterface $unwrapped = null;
+
+ /**
+ * @psalm-param non-empty-string $uuid
+ */
+ public function __construct(private string $uuid)
{
- $this->uuid = $uuid;
}
/** @psalm-pure */
@@ -105,19 +101,20 @@ final class LazyUuidFromString implements UuidInterface
/**
* {@inheritDoc}
*
- * @param string $serialized
+ * @param string $data
*
- * @psalm-param non-empty-string $serialized
+ * @psalm-param non-empty-string $data
*/
- public function unserialize($serialized): void
+ public function unserialize(string $data): void
{
- $this->uuid = $serialized;
+ $this->uuid = $data;
}
/**
* @param array{string?: string} $data
*
* @psalm-param array{string?: non-empty-string} $data
+ * @psalm-suppress UnusedMethodCall
*/
public function __unserialize(array $data): void
{
diff --git a/src/Nonstandard/Fields.php b/src/Nonstandard/Fields.php
index d5b820f..5dfe610 100644
--- a/src/Nonstandard/Fields.php
+++ b/src/Nonstandard/Fields.php
@@ -47,26 +47,19 @@ final class Fields implements FieldsInterface
use SerializableFieldsTrait;
use VariantTrait;
- /**
- * @var string
- */
- private $bytes;
-
/**
* @param string $bytes A 16-byte binary string representation of a UUID
*
* @throws InvalidArgumentException if the byte string is not exactly 16 bytes
*/
- public function __construct(string $bytes)
+ public function __construct(private string $bytes)
{
- if (strlen($bytes) !== 16) {
+ if (strlen($this->bytes) !== 16) {
throw new InvalidArgumentException(
'The byte string must be 16 bytes long; '
- . 'received ' . strlen($bytes) . ' bytes'
+ . 'received ' . strlen($this->bytes) . ' bytes'
);
}
-
- $this->bytes = $bytes;
}
public function getBytes(): string
diff --git a/src/Nonstandard/UuidBuilder.php b/src/Nonstandard/UuidBuilder.php
index 0c89277..82efd40 100644
--- a/src/Nonstandard/UuidBuilder.php
+++ b/src/Nonstandard/UuidBuilder.php
@@ -29,16 +29,6 @@ use Throwable;
*/
class UuidBuilder implements UuidBuilderInterface
{
- /**
- * @var NumberConverterInterface
- */
- private $numberConverter;
-
- /**
- * @var TimeConverterInterface
- */
- private $timeConverter;
-
/**
* @param NumberConverterInterface $numberConverter The number converter to
* use when constructing the Nonstandard\Uuid
@@ -46,11 +36,9 @@ class UuidBuilder implements UuidBuilderInterface
* for converting timestamps extracted from a UUID to Unix timestamps
*/
public function __construct(
- NumberConverterInterface $numberConverter,
- TimeConverterInterface $timeConverter
+ private NumberConverterInterface $numberConverter,
+ private TimeConverterInterface $timeConverter
) {
- $this->numberConverter = $numberConverter;
- $this->timeConverter = $timeConverter;
}
/**
diff --git a/src/Provider/Dce/SystemDceSecurityProvider.php b/src/Provider/Dce/SystemDceSecurityProvider.php
index c53b839..d5b6cf0 100644
--- a/src/Provider/Dce/SystemDceSecurityProvider.php
+++ b/src/Provider/Dce/SystemDceSecurityProvider.php
@@ -21,7 +21,6 @@ use Ramsey\Uuid\Type\Integer as IntegerObject;
use function escapeshellarg;
use function preg_split;
use function str_getcsv;
-use function strpos;
use function strrpos;
use function strtolower;
use function strtoupper;
@@ -106,15 +105,10 @@ class SystemDceSecurityProvider implements DceSecurityProviderInterface
return '';
}
- switch ($this->getOs()) {
- case 'WIN':
- return $this->getWindowsUid();
- case 'DAR':
- case 'FRE':
- case 'LIN':
- default:
- return trim((string) shell_exec('id -u'));
- }
+ return match ($this->getOs()) {
+ 'WIN' => $this->getWindowsUid(),
+ default => trim((string) shell_exec('id -u')),
+ };
}
/**
@@ -126,15 +120,10 @@ class SystemDceSecurityProvider implements DceSecurityProviderInterface
return '';
}
- switch ($this->getOs()) {
- case 'WIN':
- return $this->getWindowsGid();
- case 'DAR':
- case 'FRE':
- case 'LIN':
- default:
- return trim((string) shell_exec('id -g'));
- }
+ return match ($this->getOs()) {
+ 'WIN' => $this->getWindowsGid(),
+ default => trim((string) shell_exec('id -g')),
+ };
}
/**
@@ -144,7 +133,7 @@ class SystemDceSecurityProvider implements DceSecurityProviderInterface
{
$disabledFunctions = strtolower((string) ini_get('disable_functions'));
- return strpos($disabledFunctions, 'shell_exec') === false;
+ return !str_contains($disabledFunctions, 'shell_exec');
}
/**
diff --git a/src/Provider/Node/FallbackNodeProvider.php b/src/Provider/Node/FallbackNodeProvider.php
index fe890cc..d2eb20b 100644
--- a/src/Provider/Node/FallbackNodeProvider.php
+++ b/src/Provider/Node/FallbackNodeProvider.php
@@ -24,24 +24,18 @@ use Ramsey\Uuid\Type\Hexadecimal;
*/
class FallbackNodeProvider implements NodeProviderInterface
{
- /**
- * @var iterable
- */
- private $nodeProviders;
-
/**
* @param iterable $providers Array of node providers
*/
- public function __construct(iterable $providers)
+ public function __construct(private iterable $providers)
{
- $this->nodeProviders = $providers;
}
public function getNode(): Hexadecimal
{
$lastProviderException = null;
- foreach ($this->nodeProviders as $provider) {
+ foreach ($this->providers as $provider) {
try {
return $provider->getNode();
} catch (NodeException $exception) {
diff --git a/src/Provider/Node/StaticNodeProvider.php b/src/Provider/Node/StaticNodeProvider.php
index 51f1b02..0f7536a 100644
--- a/src/Provider/Node/StaticNodeProvider.php
+++ b/src/Provider/Node/StaticNodeProvider.php
@@ -32,10 +32,7 @@ use const STR_PAD_LEFT;
*/
class StaticNodeProvider implements NodeProviderInterface
{
- /**
- * @var Hexadecimal
- */
- private $node;
+ private Hexadecimal $node;
/**
* @param Hexadecimal $node The static node value to use
diff --git a/src/Provider/Time/FixedTimeProvider.php b/src/Provider/Time/FixedTimeProvider.php
index 90b1c6a..526c8ff 100644
--- a/src/Provider/Time/FixedTimeProvider.php
+++ b/src/Provider/Time/FixedTimeProvider.php
@@ -26,14 +26,8 @@ use Ramsey\Uuid\Type\Time;
*/
class FixedTimeProvider implements TimeProviderInterface
{
- /**
- * @var Time
- */
- private $fixedTime;
-
- public function __construct(Time $time)
+ public function __construct(private Time $time)
{
- $this->fixedTime = $time;
}
/**
@@ -43,7 +37,7 @@ class FixedTimeProvider implements TimeProviderInterface
*/
public function setUsec($value): void
{
- $this->fixedTime = new Time($this->fixedTime->getSeconds(), $value);
+ $this->time = new Time($this->time->getSeconds(), $value);
}
/**
@@ -53,11 +47,11 @@ class FixedTimeProvider implements TimeProviderInterface
*/
public function setSec($value): void
{
- $this->fixedTime = new Time($value, $this->fixedTime->getMicroseconds());
+ $this->time = new Time($value, $this->time->getMicroseconds());
}
public function getTime(): Time
{
- return $this->fixedTime;
+ return $this->time;
}
}
diff --git a/src/Rfc4122/Fields.php b/src/Rfc4122/Fields.php
index 0a6ece5..9acf810 100644
--- a/src/Rfc4122/Fields.php
+++ b/src/Rfc4122/Fields.php
@@ -46,11 +46,6 @@ final class Fields implements FieldsInterface
use VariantTrait;
use VersionTrait;
- /**
- * @var string
- */
- private $bytes;
-
/**
* @param string $bytes A 16-byte binary string representation of a UUID
*
@@ -58,17 +53,15 @@ final class Fields implements FieldsInterface
* @throws InvalidArgumentException if the byte string does not represent an RFC 4122 UUID
* @throws InvalidArgumentException if the byte string does not contain a valid version
*/
- public function __construct(string $bytes)
+ public function __construct(private string $bytes)
{
- if (strlen($bytes) !== 16) {
+ if (strlen($this->bytes) !== 16) {
throw new InvalidArgumentException(
'The byte string must be 16 bytes long; '
- . 'received ' . strlen($bytes) . ' bytes'
+ . 'received ' . strlen($this->bytes) . ' bytes'
);
}
- $this->bytes = $bytes;
-
if (!$this->isCorrectVariant()) {
throw new InvalidArgumentException(
'The byte string received does not conform to the RFC 4122 variant'
@@ -147,44 +140,34 @@ final class Fields implements FieldsInterface
*/
public function getTimestamp(): Hexadecimal
{
- switch ($this->getVersion()) {
- case Uuid::UUID_TYPE_DCE_SECURITY:
- $timestamp = sprintf(
- '%03x%04s%08s',
- hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
- $this->getTimeMid()->toString(),
- ''
- );
-
- break;
- case Uuid::UUID_TYPE_REORDERED_TIME:
- $timestamp = sprintf(
- '%08s%04s%03x',
- $this->getTimeLow()->toString(),
- $this->getTimeMid()->toString(),
- hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff
- );
-
- break;
- case Uuid::UUID_TYPE_UNIX_TIME:
- // The Unix timestamp in version 7 UUIDs is a 48-bit number,
- // but for consistency, we will return a 60-bit number, padded
- // to the left with zeros.
- $timestamp = sprintf(
- '%011s%04s',
- $this->getTimeLow()->toString(),
- $this->getTimeMid()->toString(),
- );
-
- break;
- default:
- $timestamp = sprintf(
- '%03x%04s%08s',
- hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
- $this->getTimeMid()->toString(),
- $this->getTimeLow()->toString()
- );
- }
+ $timestamp = match ($this->getVersion()) {
+ Uuid::UUID_TYPE_DCE_SECURITY => sprintf(
+ '%03x%04s%08s',
+ hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
+ $this->getTimeMid()->toString(),
+ ''
+ ),
+ Uuid::UUID_TYPE_REORDERED_TIME => sprintf(
+ '%08s%04s%03x',
+ $this->getTimeLow()->toString(),
+ $this->getTimeMid()->toString(),
+ hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff
+ ),
+ // The Unix timestamp in version 7 UUIDs is a 48-bit number,
+ // but for consistency, we will return a 60-bit number, padded
+ // to the left with zeros.
+ Uuid::UUID_TYPE_UNIX_TIME => sprintf(
+ '%011s%04s',
+ $this->getTimeLow()->toString(),
+ $this->getTimeMid()->toString(),
+ ),
+ default => sprintf(
+ '%03x%04s%08s',
+ hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
+ $this->getTimeMid()->toString(),
+ $this->getTimeLow()->toString()
+ ),
+ };
return new Hexadecimal($timestamp);
}
@@ -195,10 +178,10 @@ final class Fields implements FieldsInterface
return null;
}
- /** @var array $parts */
+ /** @var int[] $parts */
$parts = unpack('n*', $this->bytes);
- return (int) $parts[4] >> 12;
+ return $parts[4] >> 12;
}
private function isCorrectVariant(): bool
diff --git a/src/Rfc4122/UuidBuilder.php b/src/Rfc4122/UuidBuilder.php
index 895524d..859649f 100644
--- a/src/Rfc4122/UuidBuilder.php
+++ b/src/Rfc4122/UuidBuilder.php
@@ -34,8 +34,6 @@ use Throwable;
*/
class UuidBuilder implements UuidBuilderInterface
{
- private NumberConverterInterface $numberConverter;
- private TimeConverterInterface $timeConverter;
private TimeConverterInterface $unixTimeConverter;
/**
@@ -51,12 +49,10 @@ class UuidBuilder implements UuidBuilderInterface
* to Unix timestamps
*/
public function __construct(
- NumberConverterInterface $numberConverter,
- TimeConverterInterface $timeConverter,
+ private NumberConverterInterface $numberConverter,
+ private TimeConverterInterface $timeConverter,
?TimeConverterInterface $unixTimeConverter = null
) {
- $this->numberConverter = $numberConverter;
- $this->timeConverter = $timeConverter;
$this->unixTimeConverter = $unixTimeConverter ?? new UnixTimeConverter(new BrickMathCalculator());
}
diff --git a/src/Rfc4122/VariantTrait.php b/src/Rfc4122/VariantTrait.php
index 74d12ef..1041de5 100644
--- a/src/Rfc4122/VariantTrait.php
+++ b/src/Rfc4122/VariantTrait.php
@@ -19,8 +19,8 @@ use Ramsey\Uuid\Uuid;
use function decbin;
use function str_pad;
+use function str_starts_with;
use function strlen;
-use function strpos;
use function substr;
use function unpack;
@@ -64,7 +64,7 @@ trait VariantTrait
return Uuid::RFC_4122;
}
- /** @var array $parts */
+ /** @var int[] $parts */
$parts = unpack('n*', $this->getBytes());
// $parts[5] is a 16-bit, unsigned integer containing the variant bits
@@ -73,7 +73,7 @@ trait VariantTrait
// three characters (three most-significant bits) to determine the
// variant.
$binary = str_pad(
- decbin((int) $parts[5]),
+ decbin($parts[5]),
16,
'0',
STR_PAD_LEFT
@@ -82,15 +82,13 @@ trait VariantTrait
$msb = substr($binary, 0, 3);
if ($msb === '111') {
- $variant = Uuid::RESERVED_FUTURE;
+ return Uuid::RESERVED_FUTURE;
} elseif ($msb === '110') {
- $variant = Uuid::RESERVED_MICROSOFT;
- } elseif (strpos($msb, '10') === 0) {
- $variant = Uuid::RFC_4122;
- } else {
- $variant = Uuid::RESERVED_NCS;
+ return Uuid::RESERVED_MICROSOFT;
+ } elseif (str_starts_with($msb, '10')) {
+ return Uuid::RFC_4122;
}
- return $variant;
+ return Uuid::RESERVED_NCS;
}
}
diff --git a/src/Rfc4122/VersionTrait.php b/src/Rfc4122/VersionTrait.php
index fb3e3e5..316f780 100644
--- a/src/Rfc4122/VersionTrait.php
+++ b/src/Rfc4122/VersionTrait.php
@@ -49,17 +49,12 @@ trait VersionTrait
return true;
}
- switch ($this->getVersion()) {
- case Uuid::UUID_TYPE_TIME:
- case Uuid::UUID_TYPE_DCE_SECURITY:
- case Uuid::UUID_TYPE_HASH_MD5:
- case Uuid::UUID_TYPE_RANDOM:
- case Uuid::UUID_TYPE_HASH_SHA1:
- case Uuid::UUID_TYPE_REORDERED_TIME:
- case Uuid::UUID_TYPE_UNIX_TIME:
- return true;
- }
-
- return false;
+ return match ($this->getVersion()) {
+ Uuid::UUID_TYPE_TIME, Uuid::UUID_TYPE_DCE_SECURITY,
+ Uuid::UUID_TYPE_HASH_MD5, Uuid::UUID_TYPE_RANDOM,
+ Uuid::UUID_TYPE_HASH_SHA1, Uuid::UUID_TYPE_REORDERED_TIME,
+ Uuid::UUID_TYPE_UNIX_TIME => true,
+ default => false,
+ };
}
}
diff --git a/src/Type/Decimal.php b/src/Type/Decimal.php
index 0c42e63..acc5e75 100644
--- a/src/Type/Decimal.php
+++ b/src/Type/Decimal.php
@@ -35,20 +35,10 @@ use function str_starts_with;
*/
final class Decimal implements NumberInterface
{
- /**
- * @var string
- */
- private $value;
+ private string $value;
+ private bool $isNegative = false;
- /**
- * @var bool
- */
- private $isNegative = false;
-
- /**
- * @param int|float|string|self $value The decimal value to store
- */
- public function __construct($value)
+ public function __construct(float | int | string | self $value)
{
$value = (string) $value;
@@ -112,18 +102,19 @@ final class Decimal implements NumberInterface
/**
* Constructs the object from a serialized string representation
*
- * @param string $serialized The serialized string representation of the object
+ * @param string $data The serialized string representation of the object
*
- * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
- public function unserialize($serialized): void
+ public function unserialize(string $data): void
{
- $this->__construct($serialized);
+ $this->__construct($data);
}
/**
* @param array{string?: string} $data
+ *
+ * @psalm-suppress UnusedMethodCall
*/
public function __unserialize(array $data): void
{
diff --git a/src/Type/Hexadecimal.php b/src/Type/Hexadecimal.php
index fee0f85..3c8f30a 100644
--- a/src/Type/Hexadecimal.php
+++ b/src/Type/Hexadecimal.php
@@ -19,7 +19,7 @@ use ValueError;
use function ctype_xdigit;
use function sprintf;
-use function strpos;
+use function str_starts_with;
use function strtolower;
use function substr;
@@ -34,10 +34,7 @@ use function substr;
*/
final class Hexadecimal implements TypeInterface
{
- /**
- * @var string
- */
- private $value;
+ private string $value;
/**
* @param string $value The hexadecimal value to store
@@ -46,7 +43,7 @@ final class Hexadecimal implements TypeInterface
{
$value = strtolower($value);
- if (strpos($value, '0x') === 0) {
+ if (str_starts_with($value, '0x')) {
$value = substr($value, 2);
}
@@ -90,14 +87,13 @@ final class Hexadecimal implements TypeInterface
/**
* Constructs the object from a serialized string representation
*
- * @param string $serialized The serialized string representation of the object
+ * @param string $data The serialized string representation of the object
*
- * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
- public function unserialize($serialized): void
+ public function unserialize(string $data): void
{
- $this->__construct($serialized);
+ $this->__construct($data);
}
/**
diff --git a/src/Type/Integer.php b/src/Type/Integer.php
index e786efe..e41b3ca 100644
--- a/src/Type/Integer.php
+++ b/src/Type/Integer.php
@@ -40,17 +40,11 @@ final class Integer implements NumberInterface
/**
* @psalm-var numeric-string
*/
- private $value;
+ private string $value;
- /**
- * @var bool
- */
- private $isNegative = false;
+ private bool $isNegative = false;
- /**
- * @param int|float|string|self $value The integer value to store
- */
- public function __construct($value)
+ public function __construct(float | int | string | self $value)
{
$value = (string) $value;
$sign = '+';
@@ -127,14 +121,13 @@ final class Integer implements NumberInterface
/**
* Constructs the object from a serialized string representation
*
- * @param string $serialized The serialized string representation of the object
+ * @param string $data The serialized string representation of the object
*
- * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
- public function unserialize($serialized): void
+ public function unserialize(string $data): void
{
- $this->__construct($serialized);
+ $this->__construct($data);
}
/**
diff --git a/src/Type/Time.php b/src/Type/Time.php
index f9c72b5..745b5cc 100644
--- a/src/Type/Time.php
+++ b/src/Type/Time.php
@@ -33,22 +33,13 @@ use function sprintf;
*/
final class Time implements TypeInterface
{
- /**
- * @var IntegerObject
- */
- private $seconds;
+ private IntegerObject $seconds;
+ private IntegerObject $microseconds;
- /**
- * @var IntegerObject
- */
- private $microseconds;
-
- /**
- * @param int|float|string|IntegerObject $seconds
- * @param int|float|string|IntegerObject $microseconds
- */
- public function __construct($seconds, $microseconds = 0)
- {
+ public function __construct(
+ float | int | string | IntegerObject $seconds,
+ float | int | string | IntegerObject $microseconds = 0,
+ ) {
$this->seconds = new IntegerObject($seconds);
$this->microseconds = new IntegerObject($microseconds);
}
@@ -103,15 +94,14 @@ final class Time implements TypeInterface
/**
* Constructs the object from a serialized string representation
*
- * @param string $serialized The serialized string representation of the object
+ * @param string $data The serialized string representation of the object
*
- * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
- public function unserialize($serialized): void
+ public function unserialize(string $data): void
{
/** @var array{seconds?: int|float|string, microseconds?: int|float|string} $time */
- $time = json_decode($serialized, true);
+ $time = json_decode($data, true);
if (!isset($time['seconds']) || !isset($time['microseconds'])) {
throw new UnsupportedOperationException(
diff --git a/src/Uuid.php b/src/Uuid.php
index 171d126..6656aba 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -216,38 +216,19 @@ class Uuid implements UuidInterface
self::DCE_DOMAIN_ORG => 'org',
];
- /**
- * @var UuidFactoryInterface|null
- */
- private static $factory = null;
+ private static ?UuidFactoryInterface $factory = null;
/**
- * @var bool flag to detect if the UUID factory was replaced internally, which disables all optimizations
- * for the default/happy path internal scenarios
+ * @var bool flag to detect if the UUID factory was replaced internally,
+ * which disables all optimizations for the default/happy path internal
+ * scenarios
*/
- private static $factoryReplaced = false;
+ private static bool $factoryReplaced = false;
- /**
- * @var CodecInterface
- */
- protected $codec;
-
- /**
- * The fields that make up this UUID
- *
- * @var Rfc4122FieldsInterface
- */
- protected $fields;
-
- /**
- * @var NumberConverterInterface
- */
- protected $numberConverter;
-
- /**
- * @var TimeConverterInterface
- */
- protected $timeConverter;
+ protected CodecInterface $codec;
+ protected NumberConverterInterface $numberConverter;
+ protected Rfc4122FieldsInterface $fields;
+ protected TimeConverterInterface $timeConverter;
/**
* Creates a universally unique identifier (UUID) from an array of fields
@@ -320,19 +301,17 @@ class Uuid implements UuidInterface
/**
* Re-constructs the object from its serialized form
*
- * @param string $serialized The serialized PHP string to unserialize into
+ * @param string $data The serialized PHP string to unserialize into
* a UuidInterface instance
- *
- * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
*/
- public function unserialize($serialized): void
+ public function unserialize(string $data): void
{
- if (strlen($serialized) === 16) {
+ if (strlen($data) === 16) {
/** @var Uuid $uuid */
- $uuid = self::getFactory()->fromBytes($serialized);
+ $uuid = self::getFactory()->fromBytes($data);
} else {
/** @var Uuid $uuid */
- $uuid = self::getFactory()->fromString($serialized);
+ $uuid = self::getFactory()->fromString($data);
}
$this->codec = $uuid->codec;
diff --git a/src/UuidFactory.php b/src/UuidFactory.php
index f4fabdd..ab730f7 100644
--- a/src/UuidFactory.php
+++ b/src/UuidFactory.php
@@ -48,63 +48,26 @@ use const STR_PAD_LEFT;
class UuidFactory implements UuidFactoryInterface
{
- /**
- * @var CodecInterface
- */
- private $codec;
-
- /**
- * @var DceSecurityGeneratorInterface
- */
- private $dceSecurityGenerator;
-
- /**
- * @var NameGeneratorInterface
- */
- private $nameGenerator;
-
- /**
- * @var NodeProviderInterface
- */
- private $nodeProvider;
-
- /**
- * @var NumberConverterInterface
- */
- private $numberConverter;
-
- /**
- * @var RandomGeneratorInterface
- */
- private $randomGenerator;
-
- /**
- * @var TimeConverterInterface
- */
- private $timeConverter;
-
- /**
- * @var TimeGeneratorInterface
- */
- private $timeGenerator;
-
- /**
- * @var UuidBuilderInterface
- */
- private $uuidBuilder;
-
- /**
- * @var ValidatorInterface
- */
- private $validator;
-
- /** @var bool whether the feature set was provided from outside, or we can operate under "default" assumptions */
- private $isDefaultFeatureSet;
-
+ 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;
/**
- * @param FeatureSet $features A set of available features in the current environment
+ * @var bool whether the feature set was provided from outside, or we can
+ * operate under "default" assumptions
+ */
+ private bool $isDefaultFeatureSet;
+
+ /**
+ * @param FeatureSet|null $features A set of available features in the current environment
*/
public function __construct(?FeatureSet $features = null)
{
@@ -484,8 +447,12 @@ class UuidFactory implements UuidFactoryInterface
*
* @psalm-pure
*/
- private function uuidFromNsAndName($ns, string $name, int $version, string $hashAlgorithm): UuidInterface
- {
+ private function uuidFromNsAndName(
+ UuidInterface | string $ns,
+ string $name,
+ int $version,
+ string $hashAlgorithm
+ ): UuidInterface {
if (!($ns instanceof UuidInterface)) {
$ns = $this->fromString($ns);
}
diff --git a/tests/Generator/RandomLibAdapterTest.php b/tests/Generator/RandomLibAdapterTest.php
index 438f6f1..eec2176 100644
--- a/tests/Generator/RandomLibAdapterTest.php
+++ b/tests/Generator/RandomLibAdapterTest.php
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Test\Generator;
use Mockery;
+use Mockery\MockInterface;
use Ramsey\Uuid\Generator\RandomLibAdapter;
use Ramsey\Uuid\Test\TestCase;
use RandomLib\Factory as RandomLibFactory;
@@ -34,8 +35,11 @@ class RandomLibAdapterTest extends TestCase
*/
public function testAdapterWithoutGeneratorGreatesGenerator(): void
{
+ $generator = Mockery::mock(Generator::class);
+
+ /** @var RandomLibFactory&MockInterface $factory */
$factory = Mockery::mock('overload:' . RandomLibFactory::class);
- $factory->shouldReceive('getHighStrengthGenerator')->once();
+ $factory->expects()->getHighStrengthGenerator()->andReturns($generator);
$this->assertInstanceOf(RandomLibAdapter::class, new RandomLibAdapter());
}
From a180174b0e7d9083c1868c52202d35129d11b2c2 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 15 Sep 2022 22:14:34 -0500
Subject: [PATCH 45/74] fix: update validation to support versions 6 & 7
---
src/Rfc4122/FieldsInterface.php | 1 +
src/Rfc4122/Validator.php | 5 +++--
tests/Rfc4122/ValidatorTest.php | 26 +++++++++++++++++++++++---
3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/src/Rfc4122/FieldsInterface.php b/src/Rfc4122/FieldsInterface.php
index a0cc4f4..2241cf5 100644
--- a/src/Rfc4122/FieldsInterface.php
+++ b/src/Rfc4122/FieldsInterface.php
@@ -109,6 +109,7 @@ interface FieldsInterface extends BaseFieldsInterface
* 4. Randomly generated UUID
* 5. Name-based UUID hashed with SHA-1
* 6. Reordered time UUID
+ * 7. Unix Epoch time UUID
*
* This returns `null` if the UUID is not an RFC 4122 variant, since version
* is only meaningful for this variant.
diff --git a/src/Rfc4122/Validator.php b/src/Rfc4122/Validator.php
index ed43c98..6b1f0de 100644
--- a/src/Rfc4122/Validator.php
+++ b/src/Rfc4122/Validator.php
@@ -28,7 +28,7 @@ use function str_replace;
final class Validator implements ValidatorInterface
{
private const VALID_PATTERN = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-'
- . '[1-5]{1}[0-9A-Fa-f]{3}-[ABab89]{1}[0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
+ . '[1-7][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
/**
* @psalm-return non-empty-string
@@ -43,7 +43,8 @@ final class Validator implements ValidatorInterface
public function validate(string $uuid): bool
{
$uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid);
+ $uuid = strtolower($uuid);
- return $uuid === Uuid::NIL || preg_match('/' . self::VALID_PATTERN . '/Dms', $uuid);
+ return $uuid === Uuid::NIL || $uuid === Uuid::MAX || preg_match('/' . self::VALID_PATTERN . '/Dms', $uuid);
}
}
diff --git a/tests/Rfc4122/ValidatorTest.php b/tests/Rfc4122/ValidatorTest.php
index e8b9770..779de50 100644
--- a/tests/Rfc4122/ValidatorTest.php
+++ b/tests/Rfc4122/ValidatorTest.php
@@ -30,7 +30,15 @@ class ValidatorTest extends TestCase
$validator = new Validator();
foreach ($variations as $variation) {
- $this->assertSame($expected, $validator->validate($variation));
+ $this->assertSame(
+ $expected,
+ $validator->validate($variation),
+ sprintf(
+ 'Expected "%s" to be %s',
+ $variation,
+ $expected ? 'valid' : 'not valid',
+ ),
+ );
}
}
@@ -40,7 +48,7 @@ class ValidatorTest extends TestCase
public function provideValuesForValidation(): array
{
$hexMutations = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];
- $trueVersions = [1, 2, 3, 4, 5];
+ $trueVersions = [1, 2, 3, 4, 5, 6, 7];
$trueVariants = [8, 9, 'a', 'b'];
$testValues = [];
@@ -87,13 +95,25 @@ class ValidatorTest extends TestCase
'value' => "\nff6f8cb0-c57d-11e1-1b21-0800200c9a66\n",
'expected' => false,
],
+ [
+ 'value' => '00000000-0000-0000-0000-000000000000',
+ 'expected' => true,
+ ],
+ [
+ 'value' => 'ffffffff-ffff-ffff-ffff-ffffffffffff',
+ 'expected' => true,
+ ],
+ [
+ 'value' => 'FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF',
+ 'expected' => true,
+ ],
]);
}
public function testGetPattern(): void
{
$expectedPattern = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-'
- . '[1-5]{1}[0-9A-Fa-f]{3}-[ABab89]{1}[0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
+ . '[1-7][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
$validator = new Validator();
From a161a26d917604dc6d3aa25100fddf2556e9f35d Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 15 Sep 2022 22:22:46 -0500
Subject: [PATCH 46/74] chore: prepare for release 4.5.1
---
CHANGELOG.md | 7 +++++++
docs/reference/uuid.rst | 12 ++++++++++++
2 files changed, 19 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3086d5a..4332a36 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## 4.5.1 - 2022-09-16
+
+### Fixed
+
+* Update RFC 4122 validator to recognize version 6 and 7 UUIDs.
+
+
## 4.5.0 - 2022-09-15
### Added
diff --git a/docs/reference/uuid.rst b/docs/reference/uuid.rst
index 447dbad..c77ab11 100644
--- a/docs/reference/uuid.rst
+++ b/docs/reference/uuid.rst
@@ -40,6 +40,10 @@ the ramsey/uuid library.
*Deprecated.* Use :php:const:`Uuid::UUID_TYPE_REORDERED_TIME` instead.
+ .. php:const:: UUID_TYPE_UNIX_TIME
+
+ :ref:`rfc4122.version7` UUID.
+
.. php:const:: NAMESPACE_DNS
The name string is a fully-qualified domain name.
@@ -143,6 +147,14 @@ the ramsey/uuid library.
:returns: A version 6 UUID
:returntype: Ramsey\\Uuid\\Rfc4122\\UuidV6
+ .. php:staticmethod:: uuid7([$dateTime])
+
+ Generates a version 7, Unix Epoch time UUID. See :ref:`rfc4122.version7`.
+
+ :param DateTimeInterface|null $dateTime: The date from which to create the UUID instance
+ :returns: A version 7 UUID
+ :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV7
+
.. php:staticmethod:: fromString($uuid)
Creates an instance of UuidInterface from the string standard
From 59414d4e58c34508dd1fd0d61b3892f712e015a0 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Thu, 15 Sep 2022 22:35:22 -0500
Subject: [PATCH 47/74] docs: add current year replacement token to docs
---
docs/conf.py | 5 +++++
docs/copyright.rst | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/docs/conf.py b/docs/conf.py
index a647ad9..4ae4b35 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -101,3 +101,8 @@ html_context = {
"github_version": version,
"conf_py_path": "/docs/",
}
+
+current_year = datetime.date.today().strftime('%Y')
+rst_prolog = """
+.. |current_year| replace:: {0}
+""".format(current_year)
diff --git a/docs/copyright.rst b/docs/copyright.rst
index 4560ef8..9718c8c 100644
--- a/docs/copyright.rst
+++ b/docs/copyright.rst
@@ -4,7 +4,7 @@
Copyright
=========
-Copyright © 2012-2020 Ben Ramsey
+Copyright © 2012-|current_year| Ben Ramsey
This work is licensed under the Creative Commons Attribution 4.0 International
License. To view a copy of this license, visit
From 4000e896f9f5787adf0ba9fa250c179af9f7257f Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 16 Sep 2022 09:43:44 -0500
Subject: [PATCH 48/74] refactor: remove dependency on ext-ctype
---
.github/workflows/continuous-integration.yml | 6 +-
composer.json | 2 -
composer.lock | 3 +-
docs/quickstart.rst | 3 -
src/Generator/DefaultTimeGenerator.php | 4 +-
src/Type/Hexadecimal.php | 39 +++++----
src/Type/Integer.php | 86 +++++++++++---------
tests/ExpectedBehaviorTest.php | 4 +-
8 files changed, 78 insertions(+), 69 deletions(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 2236a33..5cce18a 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -91,7 +91,7 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
- extensions: bcmath, ctype, gmp, sodium, uuid
+ extensions: bcmath, gmp, sodium, uuid
coverage: "none"
ini-values: "memory_limit=-1"
@@ -118,7 +118,7 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "latest"
- extensions: bcmath, ctype, gmp, sodium, uuid
+ extensions: bcmath, gmp, sodium, uuid
coverage: "pcov"
ini-values: "memory_limit=-1"
@@ -168,7 +168,7 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
- extensions: bcmath, ctype, gmp, sodium, uuid
+ extensions: bcmath, gmp, sodium, uuid
coverage: "none"
ini-values: "memory_limit=-1"
diff --git a/composer.json b/composer.json
index 9653cad..ec7ad3b 100644
--- a/composer.json
+++ b/composer.json
@@ -10,7 +10,6 @@
],
"require": {
"php": "^8.0",
- "ext-ctype": "*",
"ext-json": "*",
"brick/math": "^0.8.8 || ^0.9 || ^0.10",
"ramsey/collection": "^1.0"
@@ -42,7 +41,6 @@
},
"suggest": {
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
- "ext-ctype": "Enables faster processing of character classification using ctype functions.",
"ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
"ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
diff --git a/composer.lock b/composer.lock
index 634dda8..a353f90 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "93dcc08db8ab52aea6a540b1fa09dcfd",
+ "content-hash": "c8193a73ae72c856bbb82703b1788499",
"packages": [
{
"name": "brick/math",
@@ -7361,7 +7361,6 @@
"prefer-lowest": false,
"platform": {
"php": "^8.0",
- "ext-ctype": "*",
"ext-json": "*"
},
"platform-dev": [],
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index bdc310e..d1ee60d 100644
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -11,9 +11,6 @@ Requirements
ramsey/uuid |version| requires the following:
* PHP 8.0+
-* `ext-ctype `_ or a polyfill that
- provides ext-ctype, such as `symfony/polyfill-ctype
- `_
* `ext-json `_
The JSON extension is normally enabled by default, but it is possible to disable
diff --git a/src/Generator/DefaultTimeGenerator.php b/src/Generator/DefaultTimeGenerator.php
index a1b39b0..ea1e2a6 100644
--- a/src/Generator/DefaultTimeGenerator.php
+++ b/src/Generator/DefaultTimeGenerator.php
@@ -23,11 +23,11 @@ use Ramsey\Uuid\Provider\TimeProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use Throwable;
-use function ctype_xdigit;
use function dechex;
use function hex2bin;
use function is_int;
use function pack;
+use function preg_match;
use function sprintf;
use function str_pad;
use function strlen;
@@ -120,7 +120,7 @@ class DefaultTimeGenerator implements TimeGeneratorInterface
$node = dechex($node);
}
- if (!ctype_xdigit((string) $node) || strlen((string) $node) > 12) {
+ if (!preg_match('/^[A-Fa-f0-9]+$/', (string) $node) || strlen((string) $node) > 12) {
throw new InvalidArgumentException('Invalid node value');
}
diff --git a/src/Type/Hexadecimal.php b/src/Type/Hexadecimal.php
index 3c8f30a..bf71ec4 100644
--- a/src/Type/Hexadecimal.php
+++ b/src/Type/Hexadecimal.php
@@ -17,10 +17,8 @@ namespace Ramsey\Uuid\Type;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use ValueError;
-use function ctype_xdigit;
+use function preg_match;
use function sprintf;
-use function str_starts_with;
-use function strtolower;
use function substr;
/**
@@ -37,23 +35,11 @@ final class Hexadecimal implements TypeInterface
private string $value;
/**
- * @param string $value The hexadecimal value to store
+ * @param self|string $value The hexadecimal value to store
*/
- public function __construct(string $value)
+ public function __construct(self | string $value)
{
- $value = strtolower($value);
-
- if (str_starts_with($value, '0x')) {
- $value = substr($value, 2);
- }
-
- if (!ctype_xdigit($value)) {
- throw new InvalidArgumentException(
- 'Value must be a hexadecimal number'
- );
- }
-
- $this->value = $value;
+ $this->value = $value instanceof self ? (string) $value : $this->prepareValue($value);
}
public function toString(): string
@@ -109,4 +95,21 @@ final class Hexadecimal implements TypeInterface
$this->unserialize($data['string']);
}
+
+ private function prepareValue(string $value): string
+ {
+ $value = strtolower($value);
+
+ if (str_starts_with($value, '0x')) {
+ $value = substr($value, 2);
+ }
+
+ if (!preg_match('/^[A-Fa-f0-9]+$/', $value)) {
+ throw new InvalidArgumentException(
+ 'Value must be a hexadecimal number'
+ );
+ }
+
+ return $value;
+ }
}
diff --git a/src/Type/Integer.php b/src/Type/Integer.php
index e41b3ca..50dac99 100644
--- a/src/Type/Integer.php
+++ b/src/Type/Integer.php
@@ -17,10 +17,10 @@ namespace Ramsey\Uuid\Type;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use ValueError;
-use function ctype_digit;
-use function ltrim;
+use function assert;
+use function is_numeric;
+use function preg_match;
use function sprintf;
-use function str_starts_with;
use function substr;
/**
@@ -46,40 +46,7 @@ final class Integer implements NumberInterface
public function __construct(float | int | string | self $value)
{
- $value = (string) $value;
- $sign = '+';
-
- // If the value contains a sign, remove it for ctype_digit() check.
- if (str_starts_with($value, '-') || str_starts_with($value, '+')) {
- $sign = substr($value, 0, 1);
- $value = substr($value, 1);
- }
-
- if (!ctype_digit($value)) {
- throw new InvalidArgumentException(
- 'Value must be a signed integer or a string containing only '
- . 'digits 0-9 and, optionally, a sign (+ or -)'
- );
- }
-
- // Trim any leading zeros.
- $value = ltrim($value, '0');
-
- // Set to zero if the string is empty after trimming zeros.
- if ($value === '') {
- $value = '0';
- }
-
- // Add the negative sign back to the value.
- if ($sign === '-' && $value !== '0') {
- $value = $sign . $value;
- $this->isNegative = true;
- }
-
- /** @psalm-var numeric-string $numericValue */
- $numericValue = $value;
-
- $this->value = $numericValue;
+ $this->value = $value instanceof self ? (string) $value : $this->prepareValue($value);
}
public function isNegative(): bool
@@ -95,6 +62,9 @@ final class Integer implements NumberInterface
return $this->value;
}
+ /**
+ * @psalm-return numeric-string
+ */
public function __toString(): string
{
return $this->toString();
@@ -143,4 +113,46 @@ final class Integer implements NumberInterface
$this->unserialize($data['string']);
}
+
+ /**
+ * @return numeric-string
+ */
+ private function prepareValue(float | int | string $value): string
+ {
+ $value = (string) $value;
+ $sign = '+';
+
+ // If the value contains a sign, remove it for digit pattern check.
+ if (str_starts_with($value, '-') || str_starts_with($value, '+')) {
+ $sign = substr($value, 0, 1);
+ $value = substr($value, 1);
+ }
+
+ if (!preg_match('/^\d+$/', $value)) {
+ throw new InvalidArgumentException(
+ 'Value must be a signed integer or a string containing only '
+ . 'digits 0-9 and, optionally, a sign (+ or -)'
+ );
+ }
+
+ // Trim any leading zeros.
+ $value = ltrim($value, '0');
+
+ // Set to zero if the string is empty after trimming zeros.
+ if ($value === '') {
+ $value = '0';
+ }
+
+ // Add the negative sign back to the value.
+ if ($sign === '-' && $value !== '0') {
+ $value = $sign . $value;
+
+ /** @psalm-suppress InaccessibleProperty */
+ $this->isNegative = true;
+ }
+
+ assert(is_numeric($value));
+
+ return $value;
+ }
}
diff --git a/tests/ExpectedBehaviorTest.php b/tests/ExpectedBehaviorTest.php
index 52a6d1e..289a5ad 100644
--- a/tests/ExpectedBehaviorTest.php
+++ b/tests/ExpectedBehaviorTest.php
@@ -119,7 +119,7 @@ class ExpectedBehaviorTest extends TestCase
$this->assertSame(2, $uuid->getVariant());
$this->assertSame((int) substr($method, -1), $uuid->getVersion());
- $this->assertTrue(ctype_digit((string) $uuid->getInteger()));
+ $this->assertSame(1, preg_match('/^\d+$/', (string) $uuid->getInteger()));
}
public function provideStaticCreationMethods()
@@ -158,7 +158,7 @@ class ExpectedBehaviorTest extends TestCase
$this->assertSame('281474976710655', (string) $uuid->getNode());
$this->assertSame('3fff', $uuid->getClockSequenceHex());
$this->assertSame('16383', (string) $uuid->getClockSequence());
- $this->assertTrue(ctype_digit((string) $uuid->getTimestamp()));
+ $this->assertSame(1, preg_match('/^\d+$/', (string) $uuid->getTimestamp()));
}
/**
From 283468905af8d3609b342506ea122ff19818f283 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Fri, 16 Sep 2022 11:45:41 -0500
Subject: [PATCH 49/74] refactor: improve string encoding performance of
non-lazy UUIDs
---
src/Codec/GuidStringCodec.php | 21 +++++++++
src/Codec/StringCodec.php | 25 ++++++-----
tests/benchmark/GuidConversionBench.php | 43 +++++++++++++++++++
.../benchmark/NonLazyUuidConversionBench.php | 39 +++++++++++++++++
4 files changed, 115 insertions(+), 13 deletions(-)
create mode 100644 tests/benchmark/GuidConversionBench.php
create mode 100644 tests/benchmark/NonLazyUuidConversionBench.php
diff --git a/src/Codec/GuidStringCodec.php b/src/Codec/GuidStringCodec.php
index f11e9d5..04872e0 100644
--- a/src/Codec/GuidStringCodec.php
+++ b/src/Codec/GuidStringCodec.php
@@ -18,6 +18,7 @@ use Ramsey\Uuid\Guid\Guid;
use Ramsey\Uuid\UuidInterface;
use function bin2hex;
+use function sprintf;
use function substr;
/**
@@ -29,6 +30,26 @@ use function substr;
*/
class GuidStringCodec extends StringCodec
{
+ public function encode(UuidInterface $uuid): string
+ {
+ $hex = bin2hex($uuid->getFields()->getBytes());
+
+ /** @var non-empty-string */
+ return sprintf(
+ '%02s%02s%02s%02s-%02s%02s-%02s%02s-%04s-%012s',
+ substr($hex, 6, 2),
+ substr($hex, 4, 2),
+ substr($hex, 2, 2),
+ substr($hex, 0, 2),
+ substr($hex, 10, 2),
+ substr($hex, 8, 2),
+ substr($hex, 14, 2),
+ substr($hex, 12, 2),
+ substr($hex, 16, 4),
+ substr($hex, 20),
+ );
+ }
+
public function decode(string $encodedUuid): UuidInterface
{
$bytes = $this->getBytes($encodedUuid);
diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php
index 4b6e4e5..95f38d2 100644
--- a/src/Codec/StringCodec.php
+++ b/src/Codec/StringCodec.php
@@ -17,12 +17,13 @@ namespace Ramsey\Uuid\Codec;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Exception\InvalidUuidStringException;
-use Ramsey\Uuid\Rfc4122\FieldsInterface;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
+use function bin2hex;
use function hex2bin;
use function implode;
+use function sprintf;
use function str_replace;
use function strlen;
use function substr;
@@ -47,19 +48,17 @@ class StringCodec implements CodecInterface
public function encode(UuidInterface $uuid): string
{
- /** @var FieldsInterface $fields */
- $fields = $uuid->getFields();
+ $hex = bin2hex($uuid->getFields()->getBytes());
- return $fields->getTimeLow()->toString()
- . '-'
- . $fields->getTimeMid()->toString()
- . '-'
- . $fields->getTimeHiAndVersion()->toString()
- . '-'
- . $fields->getClockSeqHiAndReserved()->toString()
- . $fields->getClockSeqLow()->toString()
- . '-'
- . $fields->getNode()->toString();
+ /** @var non-empty-string */
+ return sprintf(
+ '%08s-%04s-%04s-%04s-%012s',
+ substr($hex, 0, 8),
+ substr($hex, 8, 4),
+ substr($hex, 12, 4),
+ substr($hex, 16, 4),
+ substr($hex, 20),
+ );
}
/**
diff --git a/tests/benchmark/GuidConversionBench.php b/tests/benchmark/GuidConversionBench.php
new file mode 100644
index 0000000..a11842a
--- /dev/null
+++ b/tests/benchmark/GuidConversionBench.php
@@ -0,0 +1,43 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Benchmark;
+
+use Ramsey\Uuid\FeatureSet;
+use Ramsey\Uuid\Guid\Guid;
+use Ramsey\Uuid\UuidFactory;
+use Ramsey\Uuid\UuidInterface;
+
+final class GuidConversionBench
+{
+ private const UUID_BYTES = [
+ "\x1e\x94\x42\x33\x98\x10\x41\x38\x96\x22\x56\xe1\xf9\x0c\x56\xed",
+ ];
+
+ private UuidInterface $uuid;
+
+ public function __construct()
+ {
+ $factory = new UuidFactory(new FeatureSet(useGuids: true));
+
+ $this->uuid = $factory->fromBytes(self::UUID_BYTES[0]);
+
+ assert($this->uuid instanceof Guid);
+ }
+
+ public function benchStringConversionOfGuid(): void
+ {
+ $this->uuid->toString();
+ }
+}
diff --git a/tests/benchmark/NonLazyUuidConversionBench.php b/tests/benchmark/NonLazyUuidConversionBench.php
new file mode 100644
index 0000000..32d0e66
--- /dev/null
+++ b/tests/benchmark/NonLazyUuidConversionBench.php
@@ -0,0 +1,39 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Benchmark;
+
+use Ramsey\Uuid\UuidFactory;
+use Ramsey\Uuid\UuidInterface;
+
+final class NonLazyUuidConversionBench
+{
+ private const UUID_BYTES = [
+ "\x1e\x94\x42\x33\x98\x10\x41\x38\x96\x22\x56\xe1\xf9\x0c\x56\xed",
+ ];
+
+ private UuidInterface $uuid;
+
+ public function __construct()
+ {
+ $factory = new UuidFactory();
+
+ $this->uuid = $factory->fromBytes(self::UUID_BYTES[0]);
+ }
+
+ public function benchStringConversionOfUuid(): void
+ {
+ $this->uuid->toString();
+ }
+}
From fadce629acd24e79cfffabcd58361288c020aca6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 19 Sep 2022 16:17:17 -0500
Subject: [PATCH 50/74] chore(deps): bump codecov/codecov-action from 3.1.0 to
3.1.1
---
.github/workflows/continuous-integration.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 5cce18a..e286de1 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -131,7 +131,7 @@ jobs:
run: "./vendor/bin/phpunit --verbose --colors=always --coverage-text --coverage-clover build/logs/clover.xml"
- name: "Publish coverage report to Codecov"
- uses: "codecov/codecov-action@v3.1.0"
+ uses: "codecov/codecov-action@v3.1.1"
unit-tests:
name: "Unit Tests"
From 8b5d869d84c7a99400bf314e78289028fcae5456 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 26 Sep 2022 16:25:27 -0500
Subject: [PATCH 51/74] chore(deps): bump ridedott/merge-me-action from 2.10.20
to 2.10.24
---
.github/workflows/merge-dependabot-upgrades.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/merge-dependabot-upgrades.yml b/.github/workflows/merge-dependabot-upgrades.yml
index 574d7dd..6b0afad 100644
--- a/.github/workflows/merge-dependabot-upgrades.yml
+++ b/.github/workflows/merge-dependabot-upgrades.yml
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Auto-Merge
if: ${{ github.event.workflow_run.conclusion == 'success' }}
- uses: ridedott/merge-me-action@v2.10.20
+ uses: ridedott/merge-me-action@v2.10.24
with:
# This must be used as GitHub Actions token does not support pushing
# to protected branches.
From c05274984346c552b38da86089919725c46b9681 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 3 Oct 2022 16:36:25 -0500
Subject: [PATCH 52/74] chore(deps): bump ridedott/merge-me-action from 2.10.24
to 2.10.29
---
.github/workflows/merge-dependabot-upgrades.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/merge-dependabot-upgrades.yml b/.github/workflows/merge-dependabot-upgrades.yml
index 6b0afad..0719f2d 100644
--- a/.github/workflows/merge-dependabot-upgrades.yml
+++ b/.github/workflows/merge-dependabot-upgrades.yml
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Auto-Merge
if: ${{ github.event.workflow_run.conclusion == 'success' }}
- uses: ridedott/merge-me-action@v2.10.24
+ uses: ridedott/merge-me-action@v2.10.29
with:
# This must be used as GitHub Actions token does not support pushing
# to protected branches.
From f9c65d9852907775bc609827ac9e5031d19ca4b7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 17 Oct 2022 16:19:29 -0500
Subject: [PATCH 53/74] chore(deps): bump ridedott/merge-me-action from 2.10.29
to 2.10.31
---
.github/workflows/merge-dependabot-upgrades.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/merge-dependabot-upgrades.yml b/.github/workflows/merge-dependabot-upgrades.yml
index 0719f2d..d1b4e17 100644
--- a/.github/workflows/merge-dependabot-upgrades.yml
+++ b/.github/workflows/merge-dependabot-upgrades.yml
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Auto-Merge
if: ${{ github.event.workflow_run.conclusion == 'success' }}
- uses: ridedott/merge-me-action@v2.10.29
+ uses: ridedott/merge-me-action@v2.10.31
with:
# This must be used as GitHub Actions token does not support pushing
# to protected branches.
From 0ba1ffb0297f3d4d15dfadd739b1b040361ba91b Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Sat, 5 Nov 2022 16:28:33 -0500
Subject: [PATCH 54/74] fix: ensure monotonicity for version 7 UUIDs
---
composer.json | 4 +-
src/FeatureSet.php | 14 +-
src/Generator/UnixTimeGenerator.php | 149 ++++++++++++++--
src/Type/Time.php | 2 +-
src/UuidFactory.php | 19 +--
tests/Generator/UnixTimeGeneratorTest.php | 199 ++++++++++++++++++++--
tests/Type/TimeTest.php | 4 +-
tests/UuidTest.php | 59 +++++++
8 files changed, 384 insertions(+), 66 deletions(-)
diff --git a/composer.json b/composer.json
index ec7ad3b..74490af 100644
--- a/composer.json
+++ b/composer.json
@@ -90,8 +90,8 @@
"phpcbf": "phpcbf -vpw --cache=build/cache/phpcs.cache",
"phpcs": "phpcs --cache=build/cache/phpcs.cache",
"phpstan": [
- "phpstan analyse --no-progress",
- "phpstan analyse -c phpstan-tests.neon --no-progress"
+ "phpstan analyse --no-progress --memory-limit=1G",
+ "phpstan analyse -c phpstan-tests.neon --no-progress --memory-limit=1G"
],
"phpunit": "phpunit --verbose --colors=always",
"phpunit-coverage": "phpunit --verbose --colors=always --coverage-html build/coverage",
diff --git a/src/FeatureSet.php b/src/FeatureSet.php
index 6c8ccb0..b9af869 100644
--- a/src/FeatureSet.php
+++ b/src/FeatureSet.php
@@ -23,7 +23,6 @@ use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
-use Ramsey\Uuid\Converter\Time\UnixTimeConverter;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Generator\DceSecurityGenerator;
use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface;
@@ -105,7 +104,7 @@ class FeatureSet
$this->validator = new GenericValidator();
assert($this->timeProvider !== null);
- $this->unixTimeGenerator = $this->buildUnixTimeGenerator($this->timeProvider);
+ $this->unixTimeGenerator = $this->buildUnixTimeGenerator();
}
/**
@@ -339,17 +338,10 @@ class FeatureSet
/**
* Returns a Unix Epoch time generator configured for this environment
- *
- * @param TimeProviderInterface $timeProvider The time provider to use with
- * the time generator
*/
- private function buildUnixTimeGenerator(TimeProviderInterface $timeProvider): TimeGeneratorInterface
+ private function buildUnixTimeGenerator(): TimeGeneratorInterface
{
- return new UnixTimeGenerator(
- new UnixTimeConverter(new BrickMathCalculator()),
- $timeProvider,
- $this->randomGenerator,
- );
+ return new UnixTimeGenerator($this->randomGenerator);
}
/**
diff --git a/src/Generator/UnixTimeGenerator.php b/src/Generator/UnixTimeGenerator.php
index 1aef869..af94dec 100644
--- a/src/Generator/UnixTimeGenerator.php
+++ b/src/Generator/UnixTimeGenerator.php
@@ -14,39 +14,156 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
-use Ramsey\Uuid\Converter\TimeConverterInterface;
-use Ramsey\Uuid\Provider\TimeProviderInterface;
+use Brick\Math\BigInteger;
+use DateTimeImmutable;
+use DateTimeInterface;
+use Ramsey\Uuid\Type\Hexadecimal;
-use function hex2bin;
+use function hash;
+use function pack;
+use function str_pad;
+use function strlen;
+use function substr;
+use function substr_replace;
+use function unpack;
+
+use const PHP_INT_SIZE;
+use const STR_PAD_LEFT;
/**
* UnixTimeGenerator generates bytes that combine a 48-bit timestamp in
* milliseconds since the Unix Epoch with 80 random bits
+ *
+ * Code and concepts within this class are borrowed from the symfony/uid package
+ * and are used under the terms of the MIT license distributed with symfony/uid.
+ *
+ * symfony/uid is copyright (c) Fabien Potencier.
+ *
+ * @link https://symfony.com/components/Uid Symfony Uid component
+ * @link https://github.com/symfony/uid/blob/4f9f537e57261519808a7ce1d941490736522bbc/UuidV7.php Symfony UuidV7 class
+ * @link https://github.com/symfony/uid/blob/6.2/LICENSE MIT License
*/
class UnixTimeGenerator implements TimeGeneratorInterface
{
+ private static string $time = '';
+ private static ?string $seed = null;
+ private static int $seedIndex = 0;
+
+ /** @var int[] */
+ private static array $rand = [];
+
+ /** @var int[] */
+ private static array $seedParts;
+
public function __construct(
- private TimeConverterInterface $timeConverter,
- private TimeProviderInterface $timeProvider,
- private RandomGeneratorInterface $randomGenerator
+ private RandomGeneratorInterface $randomGenerator,
+ private int $intSize = PHP_INT_SIZE
) {
}
/**
+ * @param Hexadecimal|int|string|null $node Unused in this generator
+ * @param int|null $clockSeq Unused in this generator
+ * @param DateTimeInterface $dateTime A date-time instance to use when
+ * generating bytes
+ *
* @inheritDoc
*/
- public function generate($node = null, ?int $clockSeq = null): string
+ public function generate($node = null, ?int $clockSeq = null, ?DateTimeInterface $dateTime = null): string
{
- // Generate 10 random bytes to append to the string returned, since our
- // time bytes will consist of 6 bytes.
- $random = $this->randomGenerator->generate(10);
+ $time = ($dateTime ?? new DateTimeImmutable('now'))->format('Uv');
- $time = $this->timeProvider->getTime();
- $unixTimeHex = $this->timeConverter->calculateTime(
- $time->getSeconds()->toString(),
- $time->getMicroseconds()->toString(),
- );
+ if ($time > self::$time || ($dateTime !== null && $time !== self::$time)) {
+ $this->randomize($time);
+ } else {
+ $time = $this->increment();
+ }
- return hex2bin($unixTimeHex->toString()) . $random;
+ if ($this->intSize >= 8) {
+ $time = substr(pack('J', (int) $time), -6);
+ } else {
+ $time = str_pad(BigInteger::of($time)->toBytes(false), 6, "\x00", STR_PAD_LEFT);
+ }
+
+ /** @var non-empty-string */
+ return $time . pack('n*', self::$rand[1], self::$rand[2], self::$rand[3], self::$rand[4], self::$rand[5]);
+ }
+
+ private function randomize(string $time): void
+ {
+ if (self::$seed === null) {
+ $seed = $this->randomGenerator->generate(16);
+ self::$seed = $seed;
+ } else {
+ $seed = $this->randomGenerator->generate(10);
+ }
+
+ /** @var int[] $rand */
+ $rand = unpack('n*', $seed);
+ $rand[1] &= 0x03ff;
+
+ self::$rand = $rand;
+ self::$time = $time;
+ }
+
+ /**
+ * Special thanks to Nicolas Grekas for sharing the following information:
+ *
+ * Within the same ms, we increment the rand part by a random 24-bit number.
+ *
+ * Instead of getting this number from random_bytes(), which is slow, we get
+ * it by sha512-hashing self::$seed. This produces 64 bytes of entropy,
+ * which we need to split in a list of 24-bit numbers. unpack() first splits
+ * them into 16 x 32-bit numbers; we take the first byte of each of these
+ * numbers to get 5 extra 24-bit numbers. Then, we consume those numbers
+ * one-by-one and run this logic every 21 iterations.
+ *
+ * self::$rand holds the random part of the UUID, split into 5 x 16-bit
+ * numbers for x86 portability. We increment this random part by the next
+ * 24-bit number in the self::$seedParts list and decrement
+ * self::$seedIndex.
+ *
+ * @link https://twitter.com/nicolasgrekas/status/1583356938825261061 Tweet from Nicolas Grekas
+ */
+ private function increment(): string
+ {
+ if (self::$seedIndex === 0 && self::$seed !== null) {
+ self::$seed = hash('sha512', self::$seed, true);
+
+ /** @var int[] $s */
+ $s = unpack('l*', self::$seed);
+ $s[] = ($s[1] >> 8 & 0xff0000) | ($s[2] >> 16 & 0xff00) | ($s[3] >> 24 & 0xff);
+ $s[] = ($s[4] >> 8 & 0xff0000) | ($s[5] >> 16 & 0xff00) | ($s[6] >> 24 & 0xff);
+ $s[] = ($s[7] >> 8 & 0xff0000) | ($s[8] >> 16 & 0xff00) | ($s[9] >> 24 & 0xff);
+ $s[] = ($s[10] >> 8 & 0xff0000) | ($s[11] >> 16 & 0xff00) | ($s[12] >> 24 & 0xff);
+ $s[] = ($s[13] >> 8 & 0xff0000) | ($s[14] >> 16 & 0xff00) | ($s[15] >> 24 & 0xff);
+
+ self::$seedParts = $s;
+ self::$seedIndex = 21;
+ }
+
+ self::$rand[5] = 0xffff & $carry = self::$rand[5] + (self::$seedParts[self::$seedIndex--] & 0xffffff);
+ self::$rand[4] = 0xffff & $carry = self::$rand[4] + ($carry >> 16);
+ self::$rand[3] = 0xffff & $carry = self::$rand[3] + ($carry >> 16);
+ self::$rand[2] = 0xffff & $carry = self::$rand[2] + ($carry >> 16);
+ self::$rand[1] += $carry >> 16;
+
+ if (0xfc00 & self::$rand[1]) {
+ $time = self::$time;
+ $mtime = (int) substr($time, -9);
+
+ if ($this->intSize >= 8 || strlen($time) < 10) {
+ $time = (string) ((int) $time + 1);
+ } elseif ($mtime === 999999999) {
+ $time = (1 + (int) substr($time, 0, -9)) . '000000000';
+ } else {
+ $mtime++;
+ $time = substr_replace($time, str_pad((string) $mtime, 9, '0', STR_PAD_LEFT), -9);
+ }
+
+ $this->randomize($time);
+ }
+
+ return self::$time;
}
}
diff --git a/src/Type/Time.php b/src/Type/Time.php
index 745b5cc..0cedb44 100644
--- a/src/Type/Time.php
+++ b/src/Type/Time.php
@@ -56,7 +56,7 @@ final class Time implements TypeInterface
public function toString(): string
{
- return $this->seconds->toString() . '.' . $this->microseconds->toString();
+ return $this->seconds->toString() . '.' . sprintf('%06s', $this->microseconds->toString());
}
public function __toString(): string
diff --git a/src/UuidFactory.php b/src/UuidFactory.php
index ab730f7..d340ca5 100644
--- a/src/UuidFactory.php
+++ b/src/UuidFactory.php
@@ -18,7 +18,6 @@ use DateTimeInterface;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
-use Ramsey\Uuid\Converter\Time\UnixTimeConverter;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface;
use Ramsey\Uuid\Generator\DefaultTimeGenerator;
@@ -27,7 +26,6 @@ use Ramsey\Uuid\Generator\RandomGeneratorInterface;
use Ramsey\Uuid\Generator\TimeGeneratorInterface;
use Ramsey\Uuid\Generator\UnixTimeGenerator;
use Ramsey\Uuid\Lazy\LazyUuidFromString;
-use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Provider\Time\FixedTimeProvider;
use Ramsey\Uuid\Type\Hexadecimal;
@@ -396,21 +394,8 @@ class UuidFactory implements UuidFactoryInterface
*/
public function uuid7(?DateTimeInterface $dateTime = null): UuidInterface
{
- if ($dateTime !== null) {
- $timeProvider = new FixedTimeProvider(
- new Time($dateTime->format('U'), $dateTime->format('u'))
- );
-
- $timeGenerator = new UnixTimeGenerator(
- new UnixTimeConverter(new BrickMathCalculator()),
- $timeProvider,
- $this->randomGenerator,
- );
-
- $bytes = $timeGenerator->generate();
- } else {
- $bytes = $this->unixTimeGenerator->generate();
- }
+ assert($this->unixTimeGenerator instanceof UnixTimeGenerator);
+ $bytes = $this->unixTimeGenerator->generate(null, null, $dateTime);
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_UNIX_TIME);
}
diff --git a/tests/Generator/UnixTimeGeneratorTest.php b/tests/Generator/UnixTimeGeneratorTest.php
index 1b7a93d..356f99f 100644
--- a/tests/Generator/UnixTimeGeneratorTest.php
+++ b/tests/Generator/UnixTimeGeneratorTest.php
@@ -4,36 +4,201 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Test\Generator;
+use DateTimeImmutable;
use Mockery;
use Mockery\MockInterface;
-use Ramsey\Uuid\Converter\Time\UnixTimeConverter;
+use Ramsey\Uuid\Generator\RandomBytesGenerator;
use Ramsey\Uuid\Generator\RandomGeneratorInterface;
use Ramsey\Uuid\Generator\UnixTimeGenerator;
-use Ramsey\Uuid\Math\BrickMathCalculator;
-use Ramsey\Uuid\Provider\TimeProviderInterface;
use Ramsey\Uuid\Test\TestCase;
-use Ramsey\Uuid\Type\Time;
class UnixTimeGeneratorTest extends TestCase
{
+ /**
+ * @runInSeparateProcess since values are stored statically on the class
+ * @preserveGlobalState disabled
+ */
public function testGenerate(): void
{
- $unixTimeConverter = new UnixTimeConverter(new BrickMathCalculator());
-
- /** @var TimeProviderInterface&MockInterface $timeProvider */
- $timeProvider = Mockery::mock(TimeProviderInterface::class, [
- 'getTime' => new Time('1578612359', '521023'),
- ]);
+ $dateTime = new DateTimeImmutable('@1578612359.521023');
+ $expectedBytes = "\x01\x6f\x8c\xa1\x01\x61\x03\x00\xff\x00\xff\x00\xff\x00\xff\x00";
/** @var RandomGeneratorInterface&MockInterface $randomGenerator */
$randomGenerator = Mockery::mock(RandomGeneratorInterface::class);
- $randomGenerator->expects()->generate(10)->andReturns("\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00");
-
- $unixTimeGenerator = new UnixTimeGenerator($unixTimeConverter, $timeProvider, $randomGenerator);
-
- $this->assertSame(
- "\x01\x6f\x8c\xa1\x01\x61\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00",
- $unixTimeGenerator->generate(),
+ $randomGenerator->expects()->generate(16)->andReturns(
+ "\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00",
);
+
+ $unixTimeGenerator = new UnixTimeGenerator($randomGenerator);
+
+ $bytes = $unixTimeGenerator->generate(null, null, $dateTime);
+
+ $this->assertSame($expectedBytes, $bytes);
+ }
+
+ /**
+ * @runInSeparateProcess since values are stored statically on the class
+ * @preserveGlobalState disabled
+ */
+ public function testGenerateProducesMonotonicResults(): void
+ {
+ $randomGenerator = new RandomBytesGenerator();
+ $unixTimeGenerator = new UnixTimeGenerator($randomGenerator);
+
+ $previous = '';
+ for ($i = 0; $i < 25; $i++) {
+ $bytes = $unixTimeGenerator->generate();
+ $this->assertTrue($bytes > $previous);
+ }
+ }
+
+ /**
+ * @runInSeparateProcess since values are stored statically on the class
+ * @preserveGlobalState disabled
+ */
+ public function testGenerateProducesMonotonicResultsWithSameDate(): void
+ {
+ $dateTime = new DateTimeImmutable('now');
+ $randomGenerator = new RandomBytesGenerator();
+ $unixTimeGenerator = new UnixTimeGenerator($randomGenerator);
+
+ $previous = '';
+ for ($i = 0; $i < 25; $i++) {
+ $bytes = $unixTimeGenerator->generate(null, null, $dateTime);
+ $this->assertTrue($bytes > $previous);
+ }
+ }
+
+ /**
+ * @runInSeparateProcess since values are stored statically on the class
+ * @preserveGlobalState disabled
+ */
+ public function testGenerateProducesMonotonicResultsFor32BitPath(): void
+ {
+ $randomGenerator = new RandomBytesGenerator();
+ $unixTimeGenerator = new UnixTimeGenerator($randomGenerator, 4);
+
+ $previous = '';
+ for ($i = 0; $i < 25; $i++) {
+ $bytes = $unixTimeGenerator->generate();
+ $this->assertTrue($bytes > $previous);
+ }
+ }
+
+ /**
+ * @runInSeparateProcess since values are stored statically on the class
+ * @preserveGlobalState disabled
+ */
+ public function testGenerateProducesMonotonicResultsWithSameDateFor32BitPath(): void
+ {
+ $dateTime = new DateTimeImmutable('now');
+ $randomGenerator = new RandomBytesGenerator();
+ $unixTimeGenerator = new UnixTimeGenerator($randomGenerator, 4);
+
+ $previous = '';
+ for ($i = 0; $i < 25; $i++) {
+ $bytes = $unixTimeGenerator->generate(null, null, $dateTime);
+ $this->assertTrue($bytes > $previous);
+ }
+ }
+
+ /**
+ * @runInSeparateProcess since values are stored statically on the class
+ * @preserveGlobalState disabled
+ */
+ public function testGenerateProducesMonotonicResultsStartingWithAllBitsSet(): void
+ {
+ /** @var RandomGeneratorInterface&MockInterface $randomGenerator */
+ $randomGenerator = Mockery::mock(RandomGeneratorInterface::class);
+ $randomGenerator->expects()->generate(16)->andReturns(
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ );
+ $randomGenerator->expects()->generate(10)->times(24)->andReturns(
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ );
+
+ $unixTimeGenerator = new UnixTimeGenerator($randomGenerator);
+
+ $previous = '';
+ for ($i = 0; $i < 25; $i++) {
+ $bytes = $unixTimeGenerator->generate();
+ $this->assertTrue($bytes > $previous);
+ }
+ }
+
+ /**
+ * @runInSeparateProcess since values are stored statically on the class
+ * @preserveGlobalState disabled
+ */
+ public function testGenerateProducesMonotonicResultsStartingWithAllBitsSetWithSameDate(): void
+ {
+ $dateTime = new DateTimeImmutable('now');
+
+ /** @var RandomGeneratorInterface&MockInterface $randomGenerator */
+ $randomGenerator = Mockery::mock(RandomGeneratorInterface::class);
+ $randomGenerator->expects()->generate(16)->andReturns(
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ );
+ $randomGenerator->expects()->generate(10)->times(24)->andReturns(
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ );
+
+ $unixTimeGenerator = new UnixTimeGenerator($randomGenerator);
+
+ $previous = '';
+ for ($i = 0; $i < 25; $i++) {
+ $bytes = $unixTimeGenerator->generate(null, null, $dateTime);
+ $this->assertTrue($bytes > $previous);
+ }
+ }
+
+ /**
+ * @runInSeparateProcess since values are stored statically on the class
+ * @preserveGlobalState disabled
+ */
+ public function testGenerateProducesMonotonicResultsStartingWithAllBitsSetFor32BitPath(): void
+ {
+ /** @var RandomGeneratorInterface&MockInterface $randomGenerator */
+ $randomGenerator = Mockery::mock(RandomGeneratorInterface::class);
+ $randomGenerator->expects()->generate(16)->andReturns(
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ );
+ $randomGenerator->expects()->generate(10)->times(24)->andReturns(
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ );
+
+ $unixTimeGenerator = new UnixTimeGenerator($randomGenerator, 4);
+
+ $previous = '';
+ for ($i = 0; $i < 25; $i++) {
+ $bytes = $unixTimeGenerator->generate();
+ $this->assertTrue($bytes > $previous);
+ }
+ }
+
+ /**
+ * @runInSeparateProcess since values are stored statically on the class
+ * @preserveGlobalState disabled
+ */
+ public function testGenerateProducesMonotonicResultsStartingWithAllBitsSetWithSameDateFor32BitPath(): void
+ {
+ $dateTime = new DateTimeImmutable('now');
+
+ /** @var RandomGeneratorInterface&MockInterface $randomGenerator */
+ $randomGenerator = Mockery::mock(RandomGeneratorInterface::class);
+ $randomGenerator->expects()->generate(16)->andReturns(
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ );
+ $randomGenerator->expects()->generate(10)->times(24)->andReturns(
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
+ );
+
+ $unixTimeGenerator = new UnixTimeGenerator($randomGenerator, 4);
+
+ $previous = '';
+ for ($i = 0; $i < 25; $i++) {
+ $bytes = $unixTimeGenerator->generate(null, null, $dateTime);
+ $this->assertTrue($bytes > $previous);
+ }
}
}
diff --git a/tests/Type/TimeTest.php b/tests/Type/TimeTest.php
index 98287e6..62df44f 100644
--- a/tests/Type/TimeTest.php
+++ b/tests/Type/TimeTest.php
@@ -28,9 +28,9 @@ class TimeTest extends TestCase
if ($microseconds !== null) {
$params[] = $microseconds;
- $timeString .= ".{$microseconds}";
+ $timeString .= sprintf('.%06s', (string) $microseconds);
} else {
- $timeString .= '.0';
+ $timeString .= '.000000';
}
$time = new Time(...$params);
diff --git a/tests/UuidTest.php b/tests/UuidTest.php
index 06dbb4d..849b0f3 100644
--- a/tests/UuidTest.php
+++ b/tests/UuidTest.php
@@ -768,6 +768,65 @@ class UuidTest extends TestCase
);
}
+ public function testUuid7SettingTheClockBackwards(): void
+ {
+ $dates = [
+ new DateTimeImmutable('now'),
+ new DateTimeImmutable('last year'),
+ new DateTimeImmutable('1979-01-01 00:00:00.000000'),
+ ];
+
+ foreach ($dates as $dateTime) {
+ $previous = Uuid::uuid7($dateTime);
+ for ($i = 0; $i < 25; $i++) {
+ $uuid = Uuid::uuid7($dateTime);
+ $this->assertGreaterThan(0, $uuid->compareTo($previous));
+ $this->assertSame($dateTime->format('Y-m-d H:i'), $uuid->getDateTime()->format('Y-m-d H:i'));
+ $previous = $uuid;
+ }
+ }
+ }
+
+ public function testUuid7WithMinimumDateTime(): void
+ {
+ $dateTime = new DateTimeImmutable('1979-01-01 00:00:00.000000');
+
+ $uuid = Uuid::uuid7($dateTime);
+ $this->assertInstanceOf(DateTimeInterface::class, $uuid->getDateTime());
+ $this->assertSame(2, $uuid->getVariant());
+ $this->assertSame(7, $uuid->getVersion());
+ $this->assertSame(
+ '1979-01-01T00:00:00.000+00:00',
+ $uuid->getDateTime()->format(DateTimeInterface::RFC3339_EXTENDED),
+ );
+ }
+
+ public function testUuid7EachUuidIsMonotonicallyIncreasing(): void
+ {
+ $previous = Uuid::uuid7();
+
+ for ($i = 0; $i < 25; $i++) {
+ $uuid = Uuid::uuid7();
+ $now = gmdate('Y-m-d H:i');
+ $this->assertGreaterThan(0, $uuid->compareTo($previous));
+ $this->assertSame($now, $uuid->getDateTime()->format('Y-m-d H:i'));
+ $previous = $uuid;
+ }
+ }
+
+ public function testUuid7EachUuidFromSameDateTimeIsMonotonicallyIncreasing(): void
+ {
+ $dateTime = new DateTimeImmutable();
+ $previous = Uuid::uuid7($dateTime);
+
+ for ($i = 0; $i < 25; $i++) {
+ $uuid = Uuid::uuid7($dateTime);
+ $this->assertGreaterThan(0, $uuid->compareTo($previous));
+ $this->assertSame($dateTime->format('Y-m-d H:i'), $uuid->getDateTime()->format('Y-m-d H:i'));
+ $previous = $uuid;
+ }
+ }
+
/**
* Tests known version-3 UUIDs
*
From 55d8833b06af35bd880d8c855af734b454548fa3 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Sat, 5 Nov 2022 17:49:12 -0500
Subject: [PATCH 55/74] feat: support version 8, custom UUIDs
---
docs/reference.rst | 1 +
docs/reference/rfc4122-uuidv8.rst | 13 +++++++
docs/rfc4122.rst | 7 +++-
docs/rfc4122/version6.rst | 2 +-
docs/rfc4122/version7.rst | 2 +-
docs/rfc4122/version8.rst | 51 ++++++++++++++++++++++++
psalm-baseline.xml | 19 ++-------
src/Rfc4122/MaxTrait.php | 2 +-
src/Rfc4122/UuidBuilder.php | 2 +
src/Rfc4122/UuidV6.php | 2 +-
src/Rfc4122/UuidV7.php | 6 ++-
src/Rfc4122/UuidV8.php | 65 +++++++++++++++++++++++++++++++
src/Rfc4122/Validator.php | 2 +-
src/Rfc4122/VersionTrait.php | 2 +-
src/Uuid.php | 41 +++++++++++++++++--
src/UuidFactory.php | 21 ++++++++++
src/functions.php | 20 ++++++++++
tests/FunctionsTest.php | 16 ++++++++
tests/Rfc4122/UuidBuilderTest.php | 7 ++++
tests/Rfc4122/UuidV8Test.php | 57 +++++++++++++++++++++++++++
tests/Rfc4122/ValidatorTest.php | 4 +-
tests/UuidTest.php | 20 ++++++++++
22 files changed, 332 insertions(+), 30 deletions(-)
create mode 100644 docs/reference/rfc4122-uuidv8.rst
create mode 100644 docs/rfc4122/version8.rst
create mode 100644 src/Rfc4122/UuidV8.php
create mode 100644 tests/Rfc4122/UuidV8Test.php
diff --git a/docs/reference.rst b/docs/reference.rst
index 55d5c9e..d78bae5 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -19,6 +19,7 @@ Reference
reference/rfc4122-uuidv5
reference/rfc4122-uuidv6
reference/rfc4122-uuidv7
+ reference/rfc4122-uuidv8
reference/guid-fields
reference/guid-guid
reference/nonstandard-fields
diff --git a/docs/reference/rfc4122-uuidv8.rst b/docs/reference/rfc4122-uuidv8.rst
new file mode 100644
index 0000000..f2465bd
--- /dev/null
+++ b/docs/reference/rfc4122-uuidv8.rst
@@ -0,0 +1,13 @@
+.. _reference.rfc4122.uuidv8:
+
+===============
+Rfc4122\\UuidV8
+===============
+
+.. php:namespace:: Ramsey\Uuid\Rfc4122
+
+.. php:class:: UuidV8
+
+ Implements :php:interface:`Ramsey\\Uuid\\Rfc4122\\UuidInterface`.
+
+ UuidV8 represents a :ref:`version 8, custom UUID `.
diff --git a/docs/rfc4122.rst b/docs/rfc4122.rst
index 2520f97..4ef53fa 100644
--- a/docs/rfc4122.rst
+++ b/docs/rfc4122.rst
@@ -15,6 +15,7 @@ RFC 4122 UUIDs
rfc4122/version5
rfc4122/version6
rfc4122/version7
+ rfc4122/version8
`RFC 4122`_ defines five versions of UUID, while a `new Internet-Draft under
review`_ defines three new versions. Each version has different generation
@@ -57,6 +58,10 @@ Version 7: Unix Epoch Time
sortable UUID without the privacy and entropy concerns associated with
version 1 and version 6 UUIDs. For more details, see :ref:`rfc4122.version7`.
+Version 8: Custom
+ This version of UUID allows applications to generate custom identifiers in
+ an RFC-compatible format. For more details, see :doc:`rfc4122/version8`.
+
.. _RFC 4122: https://tools.ietf.org/html/rfc4122
-.. _new Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04
+.. _new Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00
diff --git a/docs/rfc4122/version6.rst b/docs/rfc4122/version6.rst
index e4b79bb..07b610e 100644
--- a/docs/rfc4122/version6.rst
+++ b/docs/rfc4122/version6.rst
@@ -208,6 +208,6 @@ need the benefit of a monotonically increasing unique identifier, see
:ref:`rfc4122.version7`.
-.. _Internet-Draft under review: https://datatracker.ietf.org/doc/draft-peabody-dispatch-new-uuid-format/
+.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6
.. _two problems that have long existed: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
.. _RFC 4122: https://tools.ietf.org/html/rfc4122
diff --git a/docs/rfc4122/version7.rst b/docs/rfc4122/version7.rst
index 1143c7c..d708467 100644
--- a/docs/rfc4122/version7.rst
+++ b/docs/rfc4122/version7.rst
@@ -167,7 +167,7 @@ This will print something like this:
ULID, unless it was converted from a version 7 UUID.
.. _ULIDs: https://github.com/ulid/spec
-.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2
+.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7
.. _two problems that have long existed: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
.. _Crockford's Base 32 algorithm: https://www.crockford.com/base32.html
.. _tuupola/base32: https://packagist.org/packages/tuupola/base32
diff --git a/docs/rfc4122/version8.rst b/docs/rfc4122/version8.rst
new file mode 100644
index 0000000..96f2b6f
--- /dev/null
+++ b/docs/rfc4122/version8.rst
@@ -0,0 +1,51 @@
+.. _rfc4122.version8:
+
+=================
+Version 8: Custom
+=================
+
+.. note::
+
+ Version 8, custom UUIDs are a new format of UUID, proposed in an
+ `Internet-Draft under review`_ at the IETF. While the draft is still going
+ through the IETF process, the version 7 format is not expected to change
+ in any way that breaks compatibility.
+
+Version 8 UUIDs allow applications to create custom UUIDs in an RFC-compatible
+way. The only requirement is the version and variant bits must be set according
+to the UUID specification. 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.
+
+.. warning::
+
+ The bytes should be a 16-byte octet string, an open blob of data that you
+ may fill with 128 bits of information. 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.
+
+.. code-block:: php
+ :caption: Generate a version 8, custom UUID
+ :name: rfc4122.version8.example
+
+ use Ramsey\Uuid\Uuid;
+
+ $uuid = Uuid::uuid8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff");
+
+ printf(
+ "UUID: %s\nVersion: %d\n",
+ $uuid->toString(),
+ $uuid->getFields()->getVersion()
+ );
+
+This will generate a version 8 UUID and print out its string representation.
+It will look something like this:
+
+.. code-block:: text
+
+ UUID: 00112233-4455-8677-8899-aabbccddeeff
+ Version: 8
+
+
+.. _Internet-Draft under review: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 85843cc..a571c8e 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -47,11 +47,6 @@
$timeGenerator
-
-
- unserialize
-
-
uuid_generate_md5
@@ -66,11 +61,6 @@
$this
-
-
- unserialize
-
-
$this
@@ -96,7 +86,9 @@
-
+
+ $this
+ $this
$this
$this
$this
@@ -123,11 +115,6 @@
NonstandardUuidV6
-
-
- unserialize
-
-
unserialize
diff --git a/src/Rfc4122/MaxTrait.php b/src/Rfc4122/MaxTrait.php
index 2ec3047..dedb727 100644
--- a/src/Rfc4122/MaxTrait.php
+++ b/src/Rfc4122/MaxTrait.php
@@ -20,7 +20,7 @@ namespace Ramsey\Uuid\Rfc4122;
* The max UUID is special form of UUID that is specified to have all 128 bits
* set to one. It is the inverse of the nil UUID.
*
- * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4 Max UUID
+ * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.10 Max UUID
*
* @psalm-immutable
*/
diff --git a/src/Rfc4122/UuidBuilder.php b/src/Rfc4122/UuidBuilder.php
index 859649f..2c2677d 100644
--- a/src/Rfc4122/UuidBuilder.php
+++ b/src/Rfc4122/UuidBuilder.php
@@ -95,6 +95,8 @@ class UuidBuilder implements UuidBuilderInterface
return new UuidV6($fields, $this->numberConverter, $codec, $this->timeConverter);
case Uuid::UUID_TYPE_UNIX_TIME:
return new UuidV7($fields, $this->numberConverter, $codec, $this->unixTimeConverter);
+ case Uuid::UUID_TYPE_CUSTOM:
+ return new UuidV8($fields, $this->numberConverter, $codec, $this->timeConverter);
}
throw new UnsupportedOperationException(
diff --git a/src/Rfc4122/UuidV6.php b/src/Rfc4122/UuidV6.php
index 9b2ddee..7e37433 100644
--- a/src/Rfc4122/UuidV6.php
+++ b/src/Rfc4122/UuidV6.php
@@ -20,7 +20,7 @@ use Ramsey\Uuid\Nonstandard\UuidV6 as NonstandardUuidV6;
* Reordered time, or version 6, UUIDs include timestamp, clock sequence, and
* node values that are combined into a 128-bit unsigned integer
*
- * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6
+ * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6 UUID Version 6
*
* @psalm-immutable
*/
diff --git a/src/Rfc4122/UuidV7.php b/src/Rfc4122/UuidV7.php
index 90c2471..5b524c4 100644
--- a/src/Rfc4122/UuidV7.php
+++ b/src/Rfc4122/UuidV7.php
@@ -22,8 +22,10 @@ use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Uuid;
/**
- * Gregorian time, or version 1, UUIDs include timestamp, clock sequence, and node
- * values that are combined into a 128-bit unsigned integer
+ * Unix Epoch time, or version 7, UUIDs include a timestamp in milliseconds
+ * since the Unix Epoch, along with random bytes
+ *
+ * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7 UUID Version 7
*
* @psalm-immutable
*/
diff --git a/src/Rfc4122/UuidV8.php b/src/Rfc4122/UuidV8.php
new file mode 100644
index 0000000..78b0290
--- /dev/null
+++ b/src/Rfc4122/UuidV8.php
@@ -0,0 +1,65 @@
+
+ * @license http://opensource.org/licenses/MIT MIT
+ */
+
+declare(strict_types=1);
+
+namespace Ramsey\Uuid\Rfc4122;
+
+use Ramsey\Uuid\Codec\CodecInterface;
+use Ramsey\Uuid\Converter\NumberConverterInterface;
+use Ramsey\Uuid\Converter\TimeConverterInterface;
+use Ramsey\Uuid\Exception\InvalidArgumentException;
+use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
+use Ramsey\Uuid\Uuid;
+
+/**
+ * Version 8, Custom UUIDs provide an RFC 4122 compatible format for
+ * experimental or vendor-specific uses
+ *
+ * The only requirement for version 8 UUIDs is that the version and variant bits
+ * must be set. Otherwise, implementations are free to set the other bits
+ * according to their needs. As a result, the uniqueness of version 8 UUIDs is
+ * implementation-specific and should not be assumed.
+ *
+ * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8 UUID Version 8
+ *
+ * @psalm-immutable
+ */
+final class UuidV8 extends Uuid implements UuidInterface
+{
+ /**
+ * Creates a version 8 (custom) UUID
+ *
+ * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
+ * @param NumberConverterInterface $numberConverter The number converter to use
+ * for converting hex values to/from integers
+ * @param CodecInterface $codec The codec to use when encoding or decoding
+ * UUID strings
+ * @param TimeConverterInterface $timeConverter The time converter to use
+ * for converting timestamps extracted from a UUID to unix timestamps
+ */
+ public function __construct(
+ Rfc4122FieldsInterface $fields,
+ NumberConverterInterface $numberConverter,
+ CodecInterface $codec,
+ TimeConverterInterface $timeConverter
+ ) {
+ if ($fields->getVersion() !== Uuid::UUID_TYPE_CUSTOM) {
+ throw new InvalidArgumentException(
+ 'Fields used to create a UuidV8 must represent a '
+ . 'version 8 (custom) UUID'
+ );
+ }
+
+ parent::__construct($fields, $numberConverter, $codec, $timeConverter);
+ }
+}
diff --git a/src/Rfc4122/Validator.php b/src/Rfc4122/Validator.php
index 6b1f0de..e82a11e 100644
--- a/src/Rfc4122/Validator.php
+++ b/src/Rfc4122/Validator.php
@@ -28,7 +28,7 @@ use function str_replace;
final class Validator implements ValidatorInterface
{
private const VALID_PATTERN = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-'
- . '[1-7][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
+ . '[1-8][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
/**
* @psalm-return non-empty-string
diff --git a/src/Rfc4122/VersionTrait.php b/src/Rfc4122/VersionTrait.php
index 316f780..0195e46 100644
--- a/src/Rfc4122/VersionTrait.php
+++ b/src/Rfc4122/VersionTrait.php
@@ -53,7 +53,7 @@ trait VersionTrait
Uuid::UUID_TYPE_TIME, Uuid::UUID_TYPE_DCE_SECURITY,
Uuid::UUID_TYPE_HASH_MD5, Uuid::UUID_TYPE_RANDOM,
Uuid::UUID_TYPE_HASH_SHA1, Uuid::UUID_TYPE_REORDERED_TIME,
- Uuid::UUID_TYPE_UNIX_TIME => true,
+ Uuid::UUID_TYPE_UNIX_TIME, Uuid::UUID_TYPE_CUSTOM => true,
default => false,
};
}
diff --git a/src/Uuid.php b/src/Uuid.php
index 6656aba..144a7a0 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -88,7 +88,7 @@ class Uuid implements UuidInterface
* The max UUID is a special form of UUID that is specified to have all 128
* bits set to one
*
- * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4 Max UUID
+ * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.10 Max UUID
*/
public const MAX = 'ffffffff-ffff-ffff-ffff-ffffffffffff';
@@ -173,17 +173,22 @@ class Uuid implements UuidInterface
/**
* Version 6 (reordered time) UUID
*
- * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1 UUID Version 6
+ * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6 UUID Version 6
*/
public const UUID_TYPE_REORDERED_TIME = 6;
/**
* Version 7 (Unix Epoch time) UUID
*
- * @link https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2 UUID Version 7
+ * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7 UUID Version 7
*/
public const UUID_TYPE_UNIX_TIME = 7;
+ /**
+ * @link https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8 UUID Version 8
+ */
+ public const UUID_TYPE_CUSTOM = 8;
+
/**
* DCE Security principal domain
*
@@ -690,4 +695,34 @@ class Uuid implements UuidInterface
'The provided factory does not support the uuid7() method',
);
}
+
+ /**
+ * 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 static function uuid8(string $bytes): UuidInterface
+ {
+ $factory = self::getFactory();
+
+ if (method_exists($factory, 'uuid8')) {
+ /** @var UuidInterface */
+ return $factory->uuid8($bytes);
+ }
+
+ throw new UnsupportedOperationException(
+ 'The provided factory does not support the uuid8() method',
+ );
+ }
}
diff --git a/src/UuidFactory.php b/src/UuidFactory.php
index d340ca5..fae8fbb 100644
--- a/src/UuidFactory.php
+++ b/src/UuidFactory.php
@@ -400,6 +400,27 @@ class UuidFactory implements UuidFactoryInterface
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
*
diff --git a/src/functions.php b/src/functions.php
index fa80f4e..2adf214 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -136,3 +136,23 @@ function v7(?DateTimeInterface $dateTime = null): string
{
return Uuid::uuid7($dateTime)->toString();
}
+
+/**
+ * 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 non-empty-string Version 7 UUID as a string
+ */
+function v8(string $bytes): string
+{
+ return Uuid::uuid8($bytes)->toString();
+}
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
index bd368ee..dfa981c 100644
--- a/tests/FunctionsTest.php
+++ b/tests/FunctionsTest.php
@@ -8,6 +8,7 @@ use DateTimeImmutable;
use DateTimeInterface;
use Ramsey\Uuid\Rfc4122\FieldsInterface;
use Ramsey\Uuid\Rfc4122\UuidV7;
+use Ramsey\Uuid\Rfc4122\UuidV8;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Uuid;
@@ -19,6 +20,7 @@ use function Ramsey\Uuid\v4;
use function Ramsey\Uuid\v5;
use function Ramsey\Uuid\v6;
use function Ramsey\Uuid\v7;
+use function Ramsey\Uuid\v8;
class FunctionsTest extends TestCase
{
@@ -118,4 +120,18 @@ class FunctionsTest extends TestCase
$this->assertInstanceOf(DateTimeInterface::class, $uuid->getDateTime());
$this->assertSame(1663195473, $uuid->getDateTime()->getTimestamp());
}
+
+ public function testV8ReturnsVersion8UuidString(): void
+ {
+ $v8 = v8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff");
+
+ /** @var UuidV8 $uuid */
+ $uuid = Uuid::fromString($v8);
+
+ /** @var FieldsInterface $fields */
+ $fields = $uuid->getFields();
+
+ $this->assertIsString($v8);
+ $this->assertSame(Uuid::UUID_TYPE_CUSTOM, $fields->getVersion());
+ }
}
diff --git a/tests/Rfc4122/UuidBuilderTest.php b/tests/Rfc4122/UuidBuilderTest.php
index 07f2d07..710ab73 100644
--- a/tests/Rfc4122/UuidBuilderTest.php
+++ b/tests/Rfc4122/UuidBuilderTest.php
@@ -23,6 +23,7 @@ use Ramsey\Uuid\Rfc4122\UuidV4;
use Ramsey\Uuid\Rfc4122\UuidV5;
use Ramsey\Uuid\Rfc4122\UuidV6;
use Ramsey\Uuid\Rfc4122\UuidV7;
+use Ramsey\Uuid\Rfc4122\UuidV8;
use Ramsey\Uuid\Test\TestCase;
use function hex2bin;
@@ -114,6 +115,12 @@ class UuidBuilderTest extends TestCase
'expectedClass' => UuidV7::class,
'expectedVersion' => 7,
],
+
+ [
+ 'uuid' => 'ff6f8cb0-c57d-81e1-9b21-0800200c9a66',
+ 'expectedClass' => UuidV8::class,
+ 'expectedVersion' => 8,
+ ],
];
}
diff --git a/tests/Rfc4122/UuidV8Test.php b/tests/Rfc4122/UuidV8Test.php
new file mode 100644
index 0000000..4f9af75
--- /dev/null
+++ b/tests/Rfc4122/UuidV8Test.php
@@ -0,0 +1,57 @@
+ $version,
+ ]);
+
+ $numberConverter = Mockery::mock(NumberConverterInterface::class);
+ $codec = Mockery::mock(CodecInterface::class);
+ $timeConverter = Mockery::mock(TimeConverterInterface::class);
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage(
+ 'Fields used to create a UuidV8 must represent a '
+ . 'version 8 (custom) UUID'
+ );
+
+ new UuidV8($fields, $numberConverter, $codec, $timeConverter);
+ }
+
+ /**
+ * @return array
+ */
+ public function provideTestVersions(): array
+ {
+ return [
+ ['version' => 0],
+ ['version' => 1],
+ ['version' => 2],
+ ['version' => 3],
+ ['version' => 4],
+ ['version' => 5],
+ ['version' => 6],
+ ['version' => 7],
+ ['version' => 9],
+ ];
+ }
+}
diff --git a/tests/Rfc4122/ValidatorTest.php b/tests/Rfc4122/ValidatorTest.php
index 779de50..b3b2e8a 100644
--- a/tests/Rfc4122/ValidatorTest.php
+++ b/tests/Rfc4122/ValidatorTest.php
@@ -48,7 +48,7 @@ class ValidatorTest extends TestCase
public function provideValuesForValidation(): array
{
$hexMutations = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f'];
- $trueVersions = [1, 2, 3, 4, 5, 6, 7];
+ $trueVersions = [1, 2, 3, 4, 5, 6, 7, 8];
$trueVariants = [8, 9, 'a', 'b'];
$testValues = [];
@@ -113,7 +113,7 @@ class ValidatorTest extends TestCase
public function testGetPattern(): void
{
$expectedPattern = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-'
- . '[1-7][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
+ . '[1-8][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
$validator = new Validator();
diff --git a/tests/UuidTest.php b/tests/UuidTest.php
index 849b0f3..4c1bd5c 100644
--- a/tests/UuidTest.php
+++ b/tests/UuidTest.php
@@ -827,6 +827,26 @@ class UuidTest extends TestCase
}
}
+ public function testUuid8(): void
+ {
+ $uuid = Uuid::uuid8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff");
+ $this->assertSame(2, $uuid->getVariant());
+ $this->assertSame(8, $uuid->getVersion());
+ }
+
+ public function testUuid8ThrowsExceptionForUnsupportedFactory(): void
+ {
+ /** @var UuidFactoryInterface&MockInterface $factory */
+ $factory = Mockery::mock(UuidFactoryInterface::class);
+
+ Uuid::setFactory($factory);
+
+ $this->expectException(UnsupportedOperationException::class);
+ $this->expectExceptionMessage('The provided factory does not support the uuid8() method');
+
+ Uuid::uuid8("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff");
+ }
+
/**
* Tests known version-3 UUIDs
*
From ad63bc700e7d021039e30ce464eba384c4a1d40f Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Sat, 5 Nov 2022 18:03:38 -0500
Subject: [PATCH 56/74] chore: prepare for version 4.6.0
---
CHANGELOG.md | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4332a36..e530708 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,23 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## 4.6.0 - 2022-11-05
+
+### Added
+
+* Add support for version 8, Unix Epoch time UUIDs, as defined in
+ [draft-ietf-uuidrev-rfc4122bis-00, section 5.8][version8]. While still an
+ Internet-Draft, version 8 is stable and unlikely to change in any way that
+ breaks compatibility.
+ * Use `Ramsey\Uuid\Uuid::uuid8()` to generate version 8 UUIDs.
+ * Version 8 UUIDs are of type `Ramsey\Uuid\Rfc4122\UuidV8`.
+ * The constant `Ramsey\Uuid\Uuid::UUID_TYPE_CUSTOM` exists for version 8 UUIDs.
+
+### Fixed
+
+* Ensure monotonicity of version 7 UUIDs.
+
+
## 4.5.1 - 2022-09-16
### Fixed
@@ -19,11 +36,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Promote version 6, reordered time UUIDs from the `Nonstandard` namespace to
the `Rfc4122` namespace. Version 6 UUIDs are defined in
- [New UUID Formats, section 5.1][version6]. While still an Internet-Draft
- version 6 is stable and unlikely to change in any way that breaks compatibility.
+ [draft-ietf-uuidrev-rfc4122bis-00, section 5.6][version6]. While still an
+ Internet-Draft version 6 is stable and unlikely to change in any way that
+ breaks compatibility.
* Add support for version 7, Unix Epoch time UUIDs, as defined in
- [New UUID Formats, section 5.2][version7]. While still an Internet-Draft,
- version 7 is stable and unlikely to change in any way that breaks compatibility.
+ [draft-ietf-uuidrev-rfc4122bis-00, section 5.7][version7]. While still an
+ Internet-Draft, version 7 is stable and unlikely to change in any way that
+ breaks compatibility.
* Use `Ramsey\Uuid\Uuid::uuid7()` to generate version 7 UUIDs.
* Version 7 UUIDs are of type `Ramsey\Uuid\Rfc4122\UuidV7`.
* The constant `Ramsey\Uuid\Uuid::UUID_TYPE_UNIX_TIME` exists for version
@@ -1363,6 +1382,7 @@ versions leading up to this release.*
[doctrine field type]: http://doctrine-dbal.readthedocs.org/en/latest/reference/types.html
[ramsey/uuid-doctrine]: https://github.com/ramsey/uuid-doctrine
[ramsey/uuid-console]: https://github.com/ramsey/uuid-console
-[version6]: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.1
-[version7]: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.2
+[version6]: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.6
+[version7]: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.7
+[version8]: https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis-00#section-5.8
[max uuids]: https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-5.4
From 8559263205f6b1edac5e346cd4cf2df9836339f1 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 21 Nov 2022 15:29:15 -0600
Subject: [PATCH 57/74] chore(deps): bump ridedott/merge-me-action from 2.10.31
to 2.10.32
---
.github/workflows/merge-dependabot-upgrades.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/merge-dependabot-upgrades.yml b/.github/workflows/merge-dependabot-upgrades.yml
index d1b4e17..c4787f6 100644
--- a/.github/workflows/merge-dependabot-upgrades.yml
+++ b/.github/workflows/merge-dependabot-upgrades.yml
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Auto-Merge
if: ${{ github.event.workflow_run.conclusion == 'success' }}
- uses: ridedott/merge-me-action@v2.10.31
+ uses: ridedott/merge-me-action@v2.10.32
with:
# This must be used as GitHub Actions token does not support pushing
# to protected branches.
From 4d4ce984ff60abc23995b6a4aea30a6cfa7ce968 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 28 Nov 2022 13:08:22 -0800
Subject: [PATCH 58/74] chore(deps): bump ridedott/merge-me-action from 2.10.32
to 2.10.34
---
.github/workflows/merge-dependabot-upgrades.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/merge-dependabot-upgrades.yml b/.github/workflows/merge-dependabot-upgrades.yml
index c4787f6..f09879a 100644
--- a/.github/workflows/merge-dependabot-upgrades.yml
+++ b/.github/workflows/merge-dependabot-upgrades.yml
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Auto-Merge
if: ${{ github.event.workflow_run.conclusion == 'success' }}
- uses: ridedott/merge-me-action@v2.10.32
+ uses: ridedott/merge-me-action@v2.10.34
with:
# This must be used as GitHub Actions token does not support pushing
# to protected branches.
From 9944a8cb6a3c481a7b49e9944393579c991835ed Mon Sep 17 00:00:00 2001
From: Ishan Vyas
Date: Sat, 3 Dec 2022 05:09:50 +0530
Subject: [PATCH 59/74] Add PHP 8.2 support (#475)
---
.github/workflows/continuous-integration.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index e286de1..7041bda 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -77,6 +77,7 @@ jobs:
php-version:
- "8.0"
- "8.1"
+ - "8.2"
steps:
- name: "Checkout repository"
@@ -144,6 +145,7 @@ jobs:
php-version:
- "8.0"
- "8.1"
+ - "8.2"
operating-system:
- "ubuntu-latest"
- "windows-latest"
From c2da47d5a63c2f9eb7eab9003a60553b0a8b7e18 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 5 Dec 2022 15:08:46 -0600
Subject: [PATCH 60/74] chore(deps): bump ridedott/merge-me-action from 2.10.34
to 2.10.37
---
.github/workflows/merge-dependabot-upgrades.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/merge-dependabot-upgrades.yml b/.github/workflows/merge-dependabot-upgrades.yml
index f09879a..1000cf3 100644
--- a/.github/workflows/merge-dependabot-upgrades.yml
+++ b/.github/workflows/merge-dependabot-upgrades.yml
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Auto-Merge
if: ${{ github.event.workflow_run.conclusion == 'success' }}
- uses: ridedott/merge-me-action@v2.10.34
+ uses: ridedott/merge-me-action@v2.10.37
with:
# This must be used as GitHub Actions token does not support pushing
# to protected branches.
From a11042f73c6e969f55e453c5d495473b0b98edc9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 12 Dec 2022 15:10:05 -0600
Subject: [PATCH 61/74] chore(deps): bump ridedott/merge-me-action from 2.10.37
to 2.10.39
---
.github/workflows/merge-dependabot-upgrades.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/merge-dependabot-upgrades.yml b/.github/workflows/merge-dependabot-upgrades.yml
index 1000cf3..cf1cb90 100644
--- a/.github/workflows/merge-dependabot-upgrades.yml
+++ b/.github/workflows/merge-dependabot-upgrades.yml
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Auto-Merge
if: ${{ github.event.workflow_run.conclusion == 'success' }}
- uses: ridedott/merge-me-action@v2.10.37
+ uses: ridedott/merge-me-action@v2.10.39
with:
# This must be used as GitHub Actions token does not support pushing
# to protected branches.
From d999e9c97e6f4ef31d794b0a9c0d6f09b86a7e75 Mon Sep 17 00:00:00 2001
From: anthony <12048285+MadeWilson@users.noreply.github.com>
Date: Mon, 19 Dec 2022 20:32:42 +0100
Subject: [PATCH 62/74] fix missing #[ReturnTypeWillChange] in Uuid (#470)
---
src/Uuid.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/Uuid.php b/src/Uuid.php
index d51e0e1..1744d28 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -213,6 +213,7 @@ class Uuid implements UuidInterface
* @return string
* @link http://php.net/manual/en/class.jsonserializable.php
*/
+ #[ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->toString();
From 087b0aa679ce669b1ea1d36288ce92d6d0c9e266 Mon Sep 17 00:00:00 2001
From: Dries Vints
Date: Mon, 19 Dec 2022 21:32:16 +0100
Subject: [PATCH 63/74] Bump minimum version of ramsey/collection (#479)
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 74490af..82b0555 100644
--- a/composer.json
+++ b/composer.json
@@ -12,7 +12,7 @@
"php": "^8.0",
"ext-json": "*",
"brick/math": "^0.8.8 || ^0.9 || ^0.10",
- "ramsey/collection": "^1.0"
+ "ramsey/collection": "^1.2"
},
"require-dev": {
"captainhook/captainhook": "^5.10",
From b9acf24bf4802e72f2074631e8abcec2f8efb4f0 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 19 Dec 2022 14:37:03 -0600
Subject: [PATCH 64/74] docs: fix GitHub Actions status badge
ci-skip
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 1862569..0db8149 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
-
+
From 9fd59bb21ca28b7f567546d8a788379edabf3790 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 19 Dec 2022 14:38:56 -0600
Subject: [PATCH 65/74] chore: update Composer lockfile
ci-skip
---
composer.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/composer.lock b/composer.lock
index a353f90..100a432 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "c8193a73ae72c856bbb82703b1788499",
+ "content-hash": "400e0b419a2e9ba982b867141254e624",
"packages": [
{
"name": "brick/math",
@@ -7364,5 +7364,5 @@
"ext-json": "*"
},
"platform-dev": [],
- "plugin-api-version": "2.2.0"
+ "plugin-api-version": "2.3.0"
}
From 5e24bfd39015e3cf9353a854fca2946a8a1e0933 Mon Sep 17 00:00:00 2001
From: Marcel Berteler
Date: Mon, 19 Dec 2022 23:18:32 +0200
Subject: [PATCH 66/74] feat: add Uuid:fromHexadecimal() (#309)
Co-authored-by: mberteler
Co-authored-by: Ben Ramsey
---
src/Uuid.php | 34 ++++++++++++++++++++++++++++++++--
src/UuidFactory.php | 10 ++++++++++
tests/UuidTest.php | 32 ++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+), 2 deletions(-)
diff --git a/src/Uuid.php b/src/Uuid.php
index 144a7a0..7cbfb17 100644
--- a/src/Uuid.php
+++ b/src/Uuid.php
@@ -14,6 +14,7 @@ declare(strict_types=1);
namespace Ramsey\Uuid;
+use BadMethodCallException;
use DateTimeInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
@@ -514,6 +515,33 @@ class Uuid implements UuidInterface
return self::getFactory()->fromDateTime($dateTime, $node, $clockSeq);
}
+ /**
+ * Creates a UUID from the Hexadecimal object
+ *
+ * @param Hexadecimal $hex Hexadecimal object representing a hexadecimal number
+ *
+ * @return UuidInterface A UuidInterface instance created from the Hexadecimal
+ * object representing a hexadecimal number
+ *
+ * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants,
+ * but under constant factory setups, this method operates in functionally pure manners
+ * @psalm-suppress MixedInferredReturnType,MixedReturnStatement
+ */
+ public static function fromHexadecimal(Hexadecimal $hex): UuidInterface
+ {
+ $factory = self::getFactory();
+
+ if (method_exists($factory, 'fromHexadecimal')) {
+ /**
+ * @phpstan-ignore-next-line
+ * @psalm-suppress UndefinedInterfaceMethod
+ */
+ return self::getFactory()->fromHexadecimal($hex);
+ }
+
+ throw new BadMethodCallException('The method fromHexadecimal() does not exist on the provided factory');
+ }
+
/**
* Creates a UUID from a 128-bit integer string
*
@@ -527,6 +555,7 @@ class Uuid implements UuidInterface
*/
public static function fromInteger(string $integer): UuidInterface
{
+ /** @psalm-suppress ImpureMethodCall */
return self::getFactory()->fromInteger($integer);
}
@@ -544,6 +573,7 @@ class Uuid implements UuidInterface
*/
public static function isValid(string $uuid): bool
{
+ /** @psalm-suppress ImpureMethodCall */
return self::getFactory()->getValidator()->validate($uuid);
}
@@ -554,7 +584,7 @@ class Uuid implements UuidInterface
* @param Hexadecimal|int|string|null $node A 48-bit number representing the
* hardware address; this number may be represented as an integer or a
* hexadecimal string
- * @param int $clockSeq A 14-bit number used to help avoid duplicates that
+ * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that
* could arise when the clock is set backwards in time or if the node ID
* changes
*
@@ -658,7 +688,7 @@ class Uuid implements UuidInterface
*
* @param Hexadecimal|null $node A 48-bit number representing the hardware
* address
- * @param int $clockSeq A 14-bit number used to help avoid duplicates that
+ * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that
* could arise when the clock is set backwards in time or if the node ID
* changes
*
diff --git a/src/UuidFactory.php b/src/UuidFactory.php
index fae8fbb..1b06ea6 100644
--- a/src/UuidFactory.php
+++ b/src/UuidFactory.php
@@ -312,6 +312,14 @@ class UuidFactory implements UuidFactoryInterface
return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME);
}
+ /**
+ * @psalm-pure
+ */
+ public function fromHexadecimal(Hexadecimal $hex): UuidInterface
+ {
+ return $this->codec->decode($hex->__toString());
+ }
+
/**
* @inheritDoc
*/
@@ -436,6 +444,7 @@ class UuidFactory implements UuidFactoryInterface
*/
public function uuid(string $bytes): UuidInterface
{
+ /** @psalm-suppress ImpurePropertyFetch */
return $this->uuidBuilder->build($this->codec, $bytes);
}
@@ -498,6 +507,7 @@ class UuidFactory implements UuidFactoryInterface
return LazyUuidFromString::fromBytes($bytes);
}
+ /** @psalm-suppress ImpureVariable */
return $this->uuid($bytes);
}
}
diff --git a/tests/UuidTest.php b/tests/UuidTest.php
index 4c1bd5c..17b62a9 100644
--- a/tests/UuidTest.php
+++ b/tests/UuidTest.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Test;
+use BadMethodCallException;
use Brick\Math\BigDecimal;
use Brick\Math\RoundingMode;
use DateTimeImmutable;
@@ -73,6 +74,37 @@ class UuidTest extends TestCase
);
}
+ public function testFromHexadecimal(): void
+ {
+ $hex = new Hexadecimal('0x1EA78DEB37CE625E8F1A025041000001');
+ $uuid = Uuid::fromHexadecimal($hex);
+ $this->assertInstanceOf(Uuid::class, $uuid);
+ $this->assertEquals('1ea78deb-37ce-625e-8f1a-025041000001', $uuid->toString());
+ }
+
+ public function testFromHexadecimalShort(): void
+ {
+ $hex = new Hexadecimal('0x1EA78DEB37CE625E8F1A0250410000');
+
+ $this->expectException(InvalidUuidStringException::class);
+ $this->expectExceptionMessage('Invalid UUID string:');
+
+ Uuid::fromHexadecimal($hex);
+ }
+
+ public function testFromHexadecimalThrowsWhenMethodDoesNotExist(): void
+ {
+ $factory = Mockery::mock(UuidFactoryInterface::class);
+ Uuid::setFactory($factory);
+
+ $hex = new Hexadecimal('0x1EA78DEB37CE625E8F1A025041000001');
+
+ $this->expectException(BadMethodCallException::class);
+ $this->expectExceptionMessage('The method fromHexadecimal() does not exist on the provided factory');
+
+ Uuid::fromHexadecimal($hex);
+ }
+
/**
* Tests that UUID and GUID's have the same textual representation but not
* the same binary representation.
From 77e33bc7be8c2f31f67cf3fcd133becc130268dc Mon Sep 17 00:00:00 2001
From: zedar187
Date: Mon, 19 Dec 2022 22:30:41 +0100
Subject: [PATCH 67/74] feat(SystemNodeProvider): dismiss zero'd mac address
(#468)
Co-authored-by: Ben Ramsey
---
src/Provider/Node/SystemNodeProvider.php | 9 ++++++---
tests/Provider/Node/SystemNodeProviderTest.php | 14 +++++++++++++-
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/src/Provider/Node/SystemNodeProvider.php b/src/Provider/Node/SystemNodeProvider.php
index d0a1e69..a03c93b 100644
--- a/src/Provider/Node/SystemNodeProvider.php
+++ b/src/Provider/Node/SystemNodeProvider.php
@@ -133,12 +133,15 @@ class SystemNodeProvider implements NodeProviderInterface
$ifconfig = (string) ob_get_clean();
- $node = '';
if (preg_match_all(self::IFCONFIG_PATTERN, $ifconfig, $matches, PREG_PATTERN_ORDER)) {
- $node = $matches[1][0] ?? '';
+ foreach ($matches[1] as $iface) {
+ if ($iface !== '00:00:00:00:00:00' && $iface !== '00-00-00-00-00-00') {
+ return $iface;
+ }
+ }
}
- return $node;
+ return '';
}
/**
diff --git a/tests/Provider/Node/SystemNodeProviderTest.php b/tests/Provider/Node/SystemNodeProviderTest.php
index cff8142..a0b292e 100644
--- a/tests/Provider/Node/SystemNodeProviderTest.php
+++ b/tests/Provider/Node/SystemNodeProviderTest.php
@@ -722,6 +722,7 @@ class SystemNodeProviderTest extends TestCase
'Without leading whitespace' => ['AA-BB-CC-DD-EE-FF '],
'Without trailing linebreak' => ["\nAA-BB-CC-DD-EE-FF"],
'Without trailing whitespace' => [' AA-BB-CC-DD-EE-FF'],
+ 'All zero MAC address' => ['00-00-00-00-00-00'],
];
}
@@ -741,6 +742,7 @@ class SystemNodeProviderTest extends TestCase
['01-23-45:67:89:ab'],
['01-23-45-67:89:ab'],
['01-23-45-67-89:ab'],
+ ['00:00:00:00:00:00'],
];
}
@@ -808,6 +810,10 @@ TXT
EHC29: flags=0<> mtu 0
XHC20: flags=0<> mtu 0
EHC26: flags=0<> mtu 0
+ aa0: flags=8863 mtu 1500
+ options=10b
+ ether 00:00:00:00:00:00
+ status: active
en0: flags=8863 mtu 1500
options=10b
ether 10:dd:b1:b4:e4:8e
@@ -874,6 +880,12 @@ TXT
WINS Proxy Enabled. . . . . . . . : No
DNS Suffix Search List. . . . . . : network.lan
+ Some kind of adapter:
+
+ Connection-specific DNS Suffix . : network.foo
+ Description . . . . . . . . . . . : Some Adapter
+ Physical Address. . . . . . . . . : 00-00-00-00-00-00
+
Ethernet adapter Ethernet:
Connection-specific DNS Suffix . : network.lan
@@ -906,6 +918,7 @@ TXT
],
'Full output - FreeBSD' => [<<<'TXT'
Name Mtu Network Address Ipkts Ierrs Idrop Opkts Oerrs Coll
+ aa0 0 00:00:00:00:00:00 0 0 0 0 0 0
em0 1500 08:00:27:71:a1:00 65514 0 0 42918 0 0
em1 1500 08:00:27:d0:60:a0 1199 0 0 535 0 0
lo0 16384 lo0 4 0 0 4 0 0
@@ -930,7 +943,6 @@ TXT
'FF:FF:FF:FF:FF:FF' => ["\nFF:FF:FF:FF:FF:FF\n", 'ffffffffffff'],
/* Incorrect variations that are also accepted */
- 'Local host' => ["\n00:00:00:00:00:00\n", '000000000000'],
'Too long -- extra character' => ["\nABC-01-23-45-67-89\n", 'bc0123456789'],
'Too long -- extra tuple' => ["\n01-AA-BB-CC-DD-EE-FF\n", '01aabbccddee'],
];
From 6456d902e4ac0fe4d98bdae523f9236174486e3a Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 19 Dec 2022 15:35:35 -0600
Subject: [PATCH 68/74] docs: fix build status badge
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 544df1a..491429d 100644
--- a/README.md
+++ b/README.md
@@ -175,7 +175,7 @@ information.
[badge-upgrade]: https://img.shields.io/packagist/v/ramsey/uuid.svg?style=flat-square&label=upgrade&colorB=darkred
[badge-license]: https://img.shields.io/packagist/l/ramsey/uuid.svg?style=flat-square&colorB=darkcyan
[badge-php]: https://img.shields.io/packagist/php-v/ramsey/uuid/3.x-dev.svg?style=flat-square&colorB=%238892BF
-[badge-build]: https://img.shields.io/github/workflow/status/ramsey/uuid/build/3.x.svg?logo=github&style=flat-square
+[badge-build]: https://img.shields.io/github/actions/workflow/status/ramsey/uuid/continuous-integration.yml?branch=3.x&logo=github&style=flat-square
[badge-coverage]: https://img.shields.io/codecov/c/gh/ramsey/uuid/3.x.svg?style=flat-square&logo=codecov
[source]: https://github.com/ramsey/uuid/tree/3.x
From 963d13717a9c4224f521961969bdf4479bc59a0e Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 19 Dec 2022 15:41:41 -0600
Subject: [PATCH 69/74] ci: update workflow for testing on PHP 8.1 and 8.2
---
.github/workflows/continuous-integration.yml | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 0a238d7..afff34a 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -13,7 +13,7 @@ jobs:
runs-on: "ubuntu-latest"
steps:
- name: "Checkout repository"
- uses: "actions/checkout@v2"
+ uses: "actions/checkout@v3"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
@@ -22,7 +22,7 @@ jobs:
coverage: "none"
- name: "Install dependencies (Composer)"
- uses: "ramsey/composer-install@v1"
+ uses: "ramsey/composer-install@v2"
- name: "Check syntax (php-parallel-lint)"
run: "./vendor/bin/parallel-lint src tests --colors"
@@ -35,7 +35,7 @@ jobs:
runs-on: "ubuntu-latest"
steps:
- name: "Checkout repository"
- uses: "actions/checkout@v2"
+ uses: "actions/checkout@v3"
- name: "Install dependencies (apt)"
run: |
@@ -52,13 +52,13 @@ jobs:
ini-values: "memory_limit=-1"
- name: "Install dependencies (Composer)"
- uses: "ramsey/composer-install@v1"
+ uses: "ramsey/composer-install@v2"
- name: "Run unit tests (PHPUnit)"
run: "./vendor/bin/phpunit --verbose --colors=always --coverage-text --coverage-clover build/logs/clover.xml"
- name: "Publish coverage report to Codecov"
- uses: "codecov/codecov-action@v1"
+ uses: "codecov/codecov-action@v3"
unit-tests:
name: "Unit Tests"
@@ -77,6 +77,8 @@ jobs:
- "7.3"
- "7.4"
- "8.0"
+ - "8.1"
+ - "8.2"
operating-system:
- "ubuntu-latest"
- "windows-latest"
@@ -103,9 +105,9 @@ jobs:
- php-version: "8.0"
extensions: ", sodium, uuid"
- php-version: "8.1"
- operating-system: "ubuntu-latest"
extensions: ", sodium, uuid"
- composer-options: "--ignore-platform-req=php"
+ - php-version: "8.2"
+ extensions: ", sodium, uuid"
steps:
- name: "Configure Git (for Windows)"
@@ -115,7 +117,7 @@ jobs:
git config --system core.eol lf
- name: "Checkout repository"
- uses: "actions/checkout@v2"
+ uses: "actions/checkout@v3"
- name: "Install dependencies (apt)"
if: ${{ matrix.operating-system == 'ubuntu-latest' }}
@@ -133,7 +135,7 @@ jobs:
ini-values: "memory_limit=-1"
- name: "Install dependencies (Composer)"
- uses: "ramsey/composer-install@v1"
+ uses: "ramsey/composer-install@v2"
with:
composer-options: "${{ matrix.composer-options }}"
From dc75aa439eb4c1b77f5379fd958b3dc0e6014178 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 19 Dec 2022 15:55:10 -0600
Subject: [PATCH 70/74] chore: prepare for release 3.9.7
---
CHANGELOG.md | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 002de3b..5c15b32 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## 3.9.7 - 2022-12-19
+
+### Fixed
+
+* Add `#[ReturnTypeWillChange]` to `Uuid::jsonSerialize()` method.
+
+
## 3.9.6 - 2021-09-25
### Fixed
From 5ed9ad582647bbc3864ef78db34bdc1afdcf9b49 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Mon, 19 Dec 2022 16:30:49 -0600
Subject: [PATCH 71/74] chore: prepare release 4.7.0
---
CHANGELOG.md | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61a9c29..7a3a3f0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## 4.7.0 - 2022-12-19
+
+### Added
+
+* Add `Uuid::fromHexadecimal()` and `UuidFactory::fromHexadecimal()`. These
+ methods are not required by the interfaces.
+
+### Fixed
+
+* Ignore MAC addresses consisting of all zeroes (i.e., `00:00:00:00:00:00`).
+
+
## 4.6.0 - 2022-11-05
### Added
From 8a3bbe4ac8ab5547ebf841e1d270f1dbe49a5e71 Mon Sep 17 00:00:00 2001
From: diego
Date: Thu, 22 Dec 2022 17:38:25 +0100
Subject: [PATCH 72/74] Fix version typo (#481)
---
docs/rfc4122/version8.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/rfc4122/version8.rst b/docs/rfc4122/version8.rst
index 96f2b6f..3f87c23 100644
--- a/docs/rfc4122/version8.rst
+++ b/docs/rfc4122/version8.rst
@@ -8,7 +8,7 @@ Version 8: Custom
Version 8, custom UUIDs are a new format of UUID, proposed in an
`Internet-Draft under review`_ at the IETF. While the draft is still going
- through the IETF process, the version 7 format is not expected to change
+ through the IETF process, the version 8 format is not expected to change
in any way that breaks compatibility.
Version 8 UUIDs allow applications to create custom UUIDs in an RFC-compatible
From e484aaeb4263397dc87f338846c41685971ae99e Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Sat, 31 Dec 2022 16:15:14 -0600
Subject: [PATCH 73/74] chore: allow use of ramsey/collection ^2.0
---
composer.json | 2 +-
composer.lock | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/composer.json b/composer.json
index 82b0555..86bccac 100644
--- a/composer.json
+++ b/composer.json
@@ -12,7 +12,7 @@
"php": "^8.0",
"ext-json": "*",
"brick/math": "^0.8.8 || ^0.9 || ^0.10",
- "ramsey/collection": "^1.2"
+ "ramsey/collection": "^1.2 || ^2.0"
},
"require-dev": {
"captainhook/captainhook": "^5.10",
diff --git a/composer.lock b/composer.lock
index 100a432..fd22cad 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "400e0b419a2e9ba982b867141254e624",
+ "content-hash": "0199024b1259b59c0544623603e0f2cf",
"packages": [
{
"name": "brick/math",
From a1acf96007170234a8399586a6e2ab8feba109d1 Mon Sep 17 00:00:00 2001
From: Ben Ramsey
Date: Sat, 31 Dec 2022 16:16:59 -0600
Subject: [PATCH 74/74] chore: prepare release 4.7.1
---
CHANGELOG.md | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7a3a3f0..7fba94b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+## 4.7.1 - 2022-12-31
+
+### Fixed
+
+* Allow the use of ramsey/collection ^2.0 with ramsey/uuid.
+
+
## 4.7.0 - 2022-12-19
### Added