diff --git a/README.md b/README.md index 1d4428b..0e539e6 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,13 @@ composer require ramsey/uuid ``` +## Upgrading to Version 4 + +See the documentation for a thorough upgrade guide: + +* [Upgrading ramsey/uuid Version 3 to 4](https://uuid.ramsey.dev/en/latest/upgrading/3-to-4.html) + + ## Documentation Please see for documentation, tips, examples, and diff --git a/composer.json b/composer.json index ec2c4ad..c453b06 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ }, "require-dev": { "codeception/aspect-mock": "^3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2", "doctrine/annotations": "^1.8", "goaop/framework": "^2", "jakub-onderka/php-parallel-lint": "^1", @@ -35,7 +35,7 @@ "phpunit/phpunit": "^8.5", "slevomat/coding-standard": "^6.0", "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "^3.7.2" + "vimeo/psalm": "3.9.4" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", diff --git a/docs/copyright.rst b/docs/copyright.rst index 4dd66dd..4560ef8 100644 --- a/docs/copyright.rst +++ b/docs/copyright.rst @@ -1,3 +1,5 @@ +.. _copyright: + ========= Copyright ========= diff --git a/docs/customize.rst b/docs/customize.rst index 637c3c9..76a61de 100644 --- a/docs/customize.rst +++ b/docs/customize.rst @@ -10,12 +10,15 @@ Customization customize/ordered-time-codec customize/timestamp-first-comb-codec + customize/calculators + customize/validators + customize/factory ramsey/uuid offers a variety of ways to modify the standard behavior of the -library through dependency injection. Using `UuidFactory`_, `FeatureSet`_, and +library through dependency injection. Using `FeatureSet`_, `UuidFactory`_, and :php:meth:`Uuid::setFactory() `, you are able -to replace just about any `codec`_, `builder`_, `converter`_, `provider`_, -`generator`_, and more. +to replace just about any `builder`_, `codec`_, `converter`_, `generator`_, +`provider`_, and more. Ordered-time Codec The ordered-time codec exists to rearrange the bytes of a version 1, @@ -27,6 +30,22 @@ Timestamp-first COMB Codec with a timestamp, so that the UUID becomes monotonically increasing. To learn more, see :ref:`customize.timestamp-first-comb-codec`. +Using a Custom Calculator + It's possible to replace the default calculator ramsey/uuid uses. If your + requirements require a different solution for making calculations, see + :ref:`customize.calculators`. + +Using a Custom Validator + If your requirements require a different level of validation or a different + UUID format, you may replace the default validator. See + :ref:`customize.validators`, to learn more. + +Replace the Default Factory + Not only are you able to inject alternate builders, codecs, etc. into the + factory and use the factory to generate UUIDs, you may also replace the + global, static factory used by the static methods on the Uuid class. To find + out how, see :ref:`customize.factory`. + .. _UuidFactory: https://github.com/ramsey/uuid/blob/master/src/UuidFactory.php .. _FeatureSet: https://github.com/ramsey/uuid/blob/master/src/FeatureSet.php diff --git a/docs/customize/calculators.rst b/docs/customize/calculators.rst new file mode 100644 index 0000000..a2bcea0 --- /dev/null +++ b/docs/customize/calculators.rst @@ -0,0 +1,75 @@ +.. _customize.calculators: + +========================= +Using a Custom Calculator +========================= + +By default, ramsey/uuid uses `brick/math`_ as its internal calculator. However, +you may change the calculator, if your needs require something else. + +To swap the default calculator with your custom one, first make an adapter that +wraps your custom calculator and implements +:php:interface:`Ramsey\\Uuid\\Math\\CalculatorInterface`. This might look +something like this: + +.. code-block:: php + :caption: Create a custom calculator wrapper that implements CalculatorInterface + :name: customize.calculators.wrapper-example + + namespace MyProject; + + use Other\OtherCalculator; + use Ramsey\Uuid\Math\CalculatorInterface; + use Ramsey\Uuid\Type\Integer as IntegerObject; + use Ramsey\Uuid\Type\NumberInterface; + + class MyUuidCalculator implements CalculatorInterface + { + private $internalCalculator; + + public function __construct(OtherCalculator $customCalculator) + { + $this->internalCalculator = $customCalculator; + } + + public function add(NumberInterface $augend, NumberInterface ...$addends): NumberInterface + { + $value = $augend->toString(); + + foreach ($addends as $addend) { + $value = $this->internalCalculator->plus($value, $addend->toString()); + } + + return new IntegerObject($value); + } + + /* ... Class truncated for brevity ... */ + + } + +The easiest way to use your custom calculator wrapper is to instantiate a new +FeatureSet, set the calculator on it, and pass the FeatureSet into a new +UuidFactory. Using the factory, you may then generate and work with UUIDs, using +your custom calculator. + +.. code-block:: php + :caption: Use your custom calculator wrapper when working with UUIDs + :name: customize.calculators.use-wrapper-example + + use MyProject\MyUuidCalculator; + use Other\OtherCalculator; + use Ramsey\Uuid\FeatureSet; + use Ramsey\Uuid\UuidFactory; + + $otherCalculator = new OtherCalculator(); + $myUuidCalculator = new MyUuidCalculator($otherCalculator); + + $featureSet = new FeatureSet(); + $featureSet->setCalculator($myUuidCalculator); + + $factory = new UuidFactory($featureSet); + + $uuid = $factory->uuid1(); + + +.. _brick/math: https://github.com/brick/math diff --git a/docs/customize/factory.rst b/docs/customize/factory.rst new file mode 100644 index 0000000..abc0551 --- /dev/null +++ b/docs/customize/factory.rst @@ -0,0 +1,93 @@ +.. _customize.factory: + +=========================== +Replace the Default Factory +=========================== + +In many of the examples throughout this documentation, we've seen how to +configure the factory and then use that factory to generate and work with UUIDs. + +For example: + +.. code-block:: php + :caption: Configure the factory and use it to generate a version 1 UUID + :name: customize.factory.example + + use Ramsey\Uuid\Codec\OrderedTimeCodec; + use Ramsey\Uuid\UuidFactory; + + $factory = new UuidFactory(); + $codec = new OrderedTimeCodec($factory->getUuidBuilder()); + + $factory->setCodec($codec); + + $orderedTimeUuid = $factory->uuid1(); + +When doing this, the default behavior of ramsey/uuid is left intact. If we call +``Uuid::uuid1()`` to generate a version 1 UUID after configuring the factory as +shown above, it won't use :ref:`OrderedTimeCodec ` +to generate the UUID. + +.. code-block:: php + :caption: The behavior differs between $factory->uuid1() and Uuid::uuid1() + :name: customize.factory.behavior-example + + $orderedTimeUuid = $factory->uuid1(); + + printf( + "UUID: %s\nBytes: %s\n\n", + $orderedTimeUuid->toString(), + bin2hex($orderedTimeUuid->getBytes()) + ); + + $uuid = Uuid::uuid1(); + + printf( + "UUID: %s\nBytes: %s\n\n", + $uuid->toString(), + bin2hex($uuid->getBytes()) + ); + +In this example, we print out details for two different UUIDs. The first was +generated with the :ref:`OrderedTimeCodec ` using +``$factory->uuid1()``. The second was generated using ``Uuid::uuid1()``. It +looks something like this: + +.. code-block:: text + + UUID: 2ff06620-6251-11ea-9791-0242ac130003 + Bytes: 11ea62512ff0662097910242ac130003 + + UUID: 2ff09730-6251-11ea-ba64-0242ac130003 + Bytes: 2ff09730625111eaba640242ac130003 + +Notice the arrangement of the bytes. The first set of bytes has been rearranged, +according to the ordered-time codec rules, but the second set of bytes remains +in the same order as the UUID string. + +*Configuring the factory does not change the default behavior.* + +If we want to change the default behavior, we must *replace* the factory used +by the Uuid static methods, and we can do this using the +:php:meth:`Uuid::setFactory() ` static method. + +.. code-block:: php + :caption: Replace the factory to globally affect Uuid behavior + :name: customize.factory.replace-factory-example + + Uuid::setFactory($factory); + + $uuid = Uuid::uuid1(); + +Now, every time we call :php:meth:`Uuid::uuid() `, +ramsey/uuid will use the factory configured with the :ref:`OrderedTimeCodec +` to generate version 1 UUIDs. + +.. warning:: + + Calling :php:meth:`Uuid::setFactory() ` to + replace the factory will change the behavior of Uuid no matter where it is + used, so keep this in mind when replacing the factory. If you replace the + factory deep inside a method somewhere, any later code that calls a static + method on :php:class:`Ramsey\\Uuid\\Uuid` will use the new factory to + generate UUIDs. diff --git a/docs/customize/validators.rst b/docs/customize/validators.rst new file mode 100644 index 0000000..db51e57 --- /dev/null +++ b/docs/customize/validators.rst @@ -0,0 +1,39 @@ +.. _customize.validators: + +======================== +Using a Custom Validator +======================== + +By default, ramsey/uuid validates UUID strings with the lenient validator +:php:class:`Ramsey\\Uuid\\Validator\\GenericValidator`. This validator ensures +the string is 36 characters, has the dashes in the correct places, and uses only +hexadecimal values. It does not ensure the string is of the RFC 4122 variant or +contains a valid version. + +The validator :php:class:`Ramsey\\Uuid\\Rfc4122\\Validator` validates UUID +strings to ensure they match the RFC 4122 variant and contain a valid version. +Since it is not enabled by default, you will need to configure ramsey/uuid to +use it, if you want stricter validation. + +.. code-block:: php + :caption: Set an alternate validator to use for Uuid::isValid() + :name: customize.validators-example + + use Ramsey\Uuid\Rfc4122\Validator as Rfc4122Validator; + use Ramsey\Uuid\Uuid; + use Ramsey\Uuid\UuidFactory; + + $factory = new UuidFactory(); + $factory->setValidator(new Rfc4122Validator()); + + Uuid::setFactory($factory); + + if (!Uuid::isValid('2bfb5006-087b-9553-5082-e8f39337ad29')) { + echo "This UUID is not valid!\n"; + } + +.. tip:: + + If you want to use your own validation, create a class that implements + :php:interface:`Ramsey\\Uuid\\Validator\\ValidatorInterface` and use the + same method to set your validator on the factory. diff --git a/docs/database.rst b/docs/database.rst index d939be5..2db1a38 100644 --- a/docs/database.rst +++ b/docs/database.rst @@ -193,6 +193,12 @@ For this reason, if you choose to use UUIDs as primary keys, it might be worth the drawbacks to use UUID bytes (i.e., ``char(16)``) instead of the string representation (see :ref:`database.bytes`). +.. hint:: + + If not using InnoDB with MySQL or MariaDB, consult your database engine + documentation to find whether it also has similar properties that will + factor into your use of UUIDs. + .. _database.uk: @@ -225,8 +231,8 @@ 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 -scattered on disk. Over time, as the database size grows, lookups will become -slower and slower. +scattered on disk (for InnoDB). Over time, as the database size grows, lookups +will become slower and slower. .. note:: diff --git a/docs/faq.rst b/docs/faq.rst index ccf55de..5342398 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -1,9 +1,15 @@ +.. _faq: + ================================= Frequently Asked Questions (FAQs) ================================= .. contents:: :local: + :depth: 1 + + +.. _faq.rhumsaa-abandoned: How do I fix "rhumsaa/uuid is abandoned" messages? ################################################## @@ -26,3 +32,101 @@ Don't panic. Simply execute the following commands with Composer: After doing so, you will have the latest ramsey/uuid package in the 2.x series, and there will be no need to modify any code; the namespace in the 2.x series is still ``Rhumsaa``. + + +.. _faq.final: + +Why does ramsey/uuid use ``final``? +################################### + +You might notice that many of the concrete classes returned in ramsey/uuid are +marked as ``final``. There are specific reasons for this choice, and I will +offer a few solutions for those looking to extend or mock the classes, for +testing purposes. + +But Why? +-------- + +.. raw:: html + +
+ +
+

via GIPHY

+ +First, let's take a look at why ramsey/uuid uses ``final``. + +UUIDs are defined by a set of rules --- published as `RFC 4122`_ --- and those +rules shouldn't change. If they do, then it's no longer a UUID --- at least not +as defined by `RFC 4122`_. + +As an example, let's think about :php:class:`Rfc4122\\UuidV1 +`. If our application wants to do something +special with this type, it might use the ``instanceof`` operator to check that a +variable is a UuidV1, or it might use a type hint on a method argument. If a +third-party library passes a UUID object to us that extends UuidV1 but +overrides some very important internal logic, then we may no longer have a +version 1 UUID. Perhaps we can all be adults and play nicely, but ramsey/uuid +cannot make any guarantees for any subclasses of UuidV1. + +However, ramsey/uuid *can* make guarantees about classes that implement +:php:interface:`UuidInterface ` or +:php:interface:`Rfc4122\\UuidInterface `. + +So, if we're working with an instance of a class that is marked ``final``, we +can guarantee that the rules for the creation of that object will not change, +even if a third-party library passes us an instance of the same class. + +This is the reason why ramsey/uuid specifies certain :ref:`argument and return +types ` that are marked ``final``. Since these are ``final``, +ramsey/uuid is able to guarantee the type of data these value objects contain. +:php:class:`Type\\Integer ` should never contain +any characters other than numeral digits, and :php:class:`Type\\Hexadecimal +` should never contain any characters other +than hexadecimal digits. If other libraries could extend these and return them +from UUID instances, then ramsey/uuid cannot guarantee their values. + +This is very similar to using strict types with ``int``, ``float``, or ``bool``. +These types cannot change, so think of final classes in ramsey/uuid as types +that cannot change. + +Overriding Behavior +------------------- + +You may override the behavior of ramsey/uuid as much as you want. Despite the +use of ``final``, the library is very flexible. Take a look at the myriad +opportunities to change how the library works: + +* :ref:`rfc4122.version1.random` +* :ref:`customize.timestamp-first-comb-codec` +* :ref:`customize.factory` +* :ref:`And more... ` + +ramsey/uuid is able to provide this flexibility through the use of `interfaces`_, +`factories`_, and `dependency injection`_. + +At the same time, ramsey/uuid is able to guarantee that neither a +:php:class:`UuidV1 ` nor a +:php:class:`UuidV4 ` nor an +:php:class:`Integer ` nor a +:php:class:`Time `, etc. will ever change because of +`downstream`_ code. + +UUIDs have specific rules that make them practically unique. ramsey/uuid ensures +that other code cannot change this expectation, while allowing your code and +third-party libraries to change how UUIDs are generated and to return different +types of UUIDs not specified by `RFC 4122`_. + +Testing With UUIDs +------------------ + +Sometimes, the use of ``final`` can throw a wrench in our ability to write +tests, but it doesn't have to be that way. To learn a few techniques for using +ramsey/uuid instances in your tests, take a look at :ref:`testing`. + + +.. _RFC 4122: https://tools.ietf.org/html/rfc4122 +.. _interfaces: https://www.php.net/interfaces +.. _factories: https://en.wikipedia.org/wiki/Factory_%28object-oriented_programming%29 +.. _dependency injection: https://en.wikipedia.org/wiki/Dependency_injection +.. _downstream: https://en.wikipedia.org/wiki/Downstream_(software_development) diff --git a/docs/index.rst b/docs/index.rst index b5a4aa8..7b24a8c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,3 +1,5 @@ +.. _index: + ================== ramsey/uuid Manual ================== @@ -21,6 +23,7 @@ Contents nonstandard database customize + testing upgrading FAQs reference diff --git a/docs/introduction.rst b/docs/introduction.rst index 90a1c78..380f66b 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -1,3 +1,5 @@ +.. _introduction: + ============ Introduction ============ diff --git a/docs/reference.rst b/docs/reference.rst index fc02b7b..00e27b6 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -27,3 +27,5 @@ Reference reference/exceptions reference/helper reference/name-based-namespaces + reference/calculators + reference/validators diff --git a/docs/reference/calculators.rst b/docs/reference/calculators.rst new file mode 100644 index 0000000..9f9167d --- /dev/null +++ b/docs/reference/calculators.rst @@ -0,0 +1,168 @@ +.. _reference.calculators: + +=========== +Calculators +=========== + +.. php:namespace:: Ramsey\Uuid\Math + +.. php:interface:: CalculatorInterface + + Provides functionality for performing mathematical calculations. + + .. php:method:: add($augend, ...$addends) + + :param Ramsey\\Uuid\\Type\\NumberInterface $augend: The first addend (the integer being added to) + :param Ramsey\\Uuid\\Type\\NumberInterface ...$addends: The additional integers to a add to the augend + :returns: The sum of all the parameters + :returntype: Ramsey\\Uuid\\Type\\NumberInterface + + .. php:method:: subtract($minuend, ...$subtrahends) + + :param Ramsey\\Uuid\\Type\\NumberInterface $minuend: The integer being subtracted from + :param Ramsey\\Uuid\\Type\\NumberInterface ...$subtrahends: The integers to subtract from the minuend + :returns: The difference after subtracting all parameters + :returntype: Ramsey\\Uuid\\Type\\NumberInterface + + .. php:method:: multiply($multiplicand, ...$multipliers) + + :param Ramsey\\Uuid\\Type\\NumberInterface $multiplicand: The integer to be multiplied + :param Ramsey\\Uuid\\Type\\NumberInterface ...$multipliers: The factors by which to multiply the multiplicand + :returns: The product of multiplying all the provided parameters + :returntype: Ramsey\\Uuid\\Type\\NumberInterface + + .. php:method:: divide($roundingMode, $scale, $dividend, ...$divisors) + + :param int $roundingMode: The strategy for rounding the quotient; one of the :php:class:`Ramsey\\Uuid\\Math\\RoundingMode` constants + :param int $scale: The scale to use for the operation + :param Ramsey\\Uuid\\Type\\NumberInterface $dividend: The integer to be divided + :param Ramsey\\Uuid\\Type\\NumberInterface ...$divisors: The integers to divide ``$dividend`` by, in the order in which the division operations should take place (left-to-right) + :returns: The quotient of dividing the provided parameters left-to-right + :returntype: Ramsey\\Uuid\\Type\\NumberInterface + + + .. php:method:: fromBase($value, $base) + + Converts a value from an arbitrary base to a base-10 integer value. + + :param string $value: The value to convert + :param int $base: The base to convert from (i.e., 2, 16, 32, etc.) + :returns: The base-10 integer value of the converted value + :returntype: Ramsey\\Uuid\\Type\\Integer + + .. php:method:: toBase($value, $base) + + Converts a base-10 integer value to an arbitrary base. + + :param Ramsey\\Uuid\\Type\\Integer $value: The integer value to convert + :param int $base: The base to convert to (i.e., 2, 16, 32, etc.) + :returns: The value represented in the specified base + :returntype: ``string`` + + .. php:method:: toHexadecimal($value) + + Converts an Integer instance to a Hexadecimal instance. + + :param Ramsey\\Uuid\\Type\\Integer $value: The Integer to convert to Hexadecimal + :returntype: Ramsey\\Uuid\\Type\\Hexadecimal + + .. php:method:: toInteger($value) + + Converts a Hexadecimal instance to an Integer instance. + + :param Ramsey\\Uuid\\Type\\Hexadecimal $value: The Hexadecimal to convert to Integer + :returntype: Ramsey\\Uuid\\Type\\Integer + + +.. php:class:: RoundingMode + + .. php:const:: UNNECESSARY + + Asserts that the requested operation has an exact result, hence no + rounding is necessary. + + .. php:const:: UP + + Rounds away from zero. + + Always increments the digit prior to a nonzero discarded fraction. + Note that this rounding mode never decreases the magnitude of the + calculated value. + + .. php:const:: DOWN + + Rounds towards zero. + + Never increments the digit prior to a discarded fraction (i.e., + truncates). Note that this rounding mode never increases the magnitude of + the calculated value. + + .. php:const:: CEILING + + Rounds towards positive infinity. + + If the result is positive, behaves as for :php:const:`UP + `; if negative, behaves as for + :php:const:`DOWN `. Note that + this rounding mode never decreases the calculated value. + + .. php:const:: FLOOR + + Rounds towards negative infinity. + + If the result is positive, behave as for :php:const:`DOWN + `; if negative, behave as for + :php:const:`UP `. Note that this + rounding mode never increases the calculated value. + + .. php:const:: HALF_UP + + Rounds towards "nearest neighbor" unless both neighbors are equidistant, + in which case round up. + + Behaves as for :php:const:`UP ` if + the discarded fraction is >= 0.5; otherwise, behaves as for + :php:const:`DOWN `. Note that + this is the rounding mode commonly taught at school. + + .. php:const:: HALF_DOWN + + Rounds towards "nearest neighbor" unless both neighbors are equidistant, + in which case round down. + + Behaves as for :php:const:`UP ` if + the discarded fraction is > 0.5; otherwise, behaves as for + :php:const:`DOWN `. + + .. php:const:: HALF_CEILING + + Rounds towards "nearest neighbor" unless both neighbors are equidistant, + in which case round towards positive infinity. + + If the result is positive, behaves as for :php:const:`HALF_UP + `; if negative, behaves as + for :php:const:`HALF_DOWN `. + + .. php:const:: HALF_FLOOR + + Rounds towards "nearest neighbor" unless both neighbors are equidistant, + in which case round towards negative infinity. + + If the result is positive, behaves as for :php:const:`HALF_DOWN + `; if negative, behaves as + for :php:const:`HALF_UP `. + + .. php:const:: HALF_EVEN + + Rounds towards the "nearest neighbor" unless both neighbors are + equidistant, in which case rounds towards the even neighbor. + + Behaves as for :php:const:`HALF_UP ` + if the digit to the left of the discarded fraction is odd; behaves as + for :php:const:`HALF_DOWN ` + if it's even. + + Note that this is the rounding mode that statistically minimizes + cumulative error when applied repeatedly over a sequence of calculations. + It is sometimes known as "Banker's rounding", and is chiefly used in the + USA. diff --git a/docs/reference/uuidinterface.rst b/docs/reference/uuidinterface.rst index b27d2bd..02c1819 100644 --- a/docs/reference/uuidinterface.rst +++ b/docs/reference/uuidinterface.rst @@ -46,3 +46,8 @@ UuidInterface :returns: The string standard representation of the UUID. :returntype: ``string`` + + .. php:method:: __toString() + + :returns: The string standard representation of the UUID. + :returntype: ``string`` diff --git a/docs/reference/validators.rst b/docs/reference/validators.rst new file mode 100644 index 0000000..dc51adc --- /dev/null +++ b/docs/reference/validators.rst @@ -0,0 +1,34 @@ +.. _reference.validators: + +========== +Validators +========== + +.. php:namespace:: Ramsey\Uuid\Validator + +.. php:interface:: ValidatorInterface + + .. php:method:: getPattern() + + :returns: The regular expression pattern used by this validator + :returntype: ``string`` + + .. php:method:: validate($uuid) + + :param string $uuid: The string to validate as a UUID + :returns: True if the provided string represents a UUID, false otherwise + :returntype: ``bool`` + +.. php:class:: GenericValidator + + Implements :php:interface:`Ramsey\\Uuid\\Validator\\ValidatorInterface`. + + GenericValidator validates strings as UUIDs of any variant. + +.. php:namespace:: Ramsey\Uuid\Rfc4122 + +.. php:class:: Validator + + Implements :php:interface:`Ramsey\\Uuid\\Validator\\ValidatorInterface`. + + Rfc4122\Validator validates strings as UUIDs of the RFC 4122 variant. diff --git a/docs/testing.rst b/docs/testing.rst new file mode 100644 index 0000000..34bf6eb --- /dev/null +++ b/docs/testing.rst @@ -0,0 +1,199 @@ +.. _testing: + +================== +Testing With UUIDs +================== + +One problem with the use of ``final`` is the inability to create a `mock object`_ +to use in tests. However, the following techniques should help with testing. + +.. tip:: + + To learn why ramsey/uuid uses ``final``, take a look at :ref:`faq.final`. + + +.. _testing.inject: + +Inject a UUID of a Specific Type +-------------------------------- + +Let's say we have a method that uses a type hint for :php:class:`UuidV1 +`. + +.. code-block:: php + + public function tellTime(UuidV1 $uuid): string + { + return $uuid->getDateTime()->format('Y-m-d H:i:s'); + } + +Since this method uses UuidV1 as the type hint, we're not able to pass another +object that implements UuidInterface, and we cannot extend or mock UuidV1, so +how do we test this? + +One way is to use :php:meth:`Uuid::uuid1() ` to +create a regular UuidV1 instance and pass it. + +.. code-block:: php + + public function testTellTime(): void + { + $uuid = Uuid::uuid1(); + $myObj = new MyClass(); + + $this->assertIsString($myObj->tellTime($uuid)); + } + +This might satisfy our testing needs if we only want to assert that the method +returns a string. If we want to test for a specific string, we can do that, too, +by generating a UUID ahead of time and using it as a known value. + +.. code-block:: php + + public function testTellTime(): void + { + // We generated this version 1 UUID ahead of time and know the + // exact date and time it contains, so we can use it to test the + // return value of our method. + $uuid = Uuid::fromString('177ef0d8-6630-11ea-b69a-0242ac130003'); + $myObj = new MyClass(); + + $this->assertSame('2020-03-14 20:12:12', $myObj->tellTime($uuid)); + } + +.. note:: + + These examples assume the use of `PHPUnit`_ for tests. The concepts will + work no matter what testing framework you use. + + +.. _testing.static: + +Returning Specific UUIDs From a Static Method +--------------------------------------------- + +Sometimes, rather than pass UUIDs as method arguments, we might call the static +methods on the Uuid class from inside the method we want to test. This can be +tricky to test. + +.. code-block:: php + + public function tellTime(): string + { + $uuid = Uuid::uuid1(); + + return $uuid->getDateTime()->format('Y-m-d H:i:s'); + } + +We can call this in a test and assert that it returns a string, but we can't +return a specific UUID value from the static method call --- or can we? + +We can do this by :ref:`overriding the default factory `. + +First, we create our own factory class for testing. In this example, we extend +UuidFactory, but you may create your own separate factory class for testing, as +long as you implement :php:interface:`Ramsey\\Uuid\\UuidFactoryInterface`. + +.. code-block:: php + + namespace MyPackage; + + use Ramsey\Uuid\UuidFactory; + use Ramsey\Uuid\UuidInterface; + + class MyTestUuidFactory extends UuidFactory + { + public $uuid1; + + public function uuid1($node = null, ?int $clockSeq = null): UuidInterface + { + return $this->uuid1; + } + } + +Now, from our tests, we can replace the default factory with our new factory, +and we can even change the value returned by the :php:meth:`uuid1() +` method for our tests. + +.. code-block:: php + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testTellTime(): void + { + $factory = new MyTestUuidFactory(); + Uuid::setFactory($factory); + + $myObj = new MyClass(); + + $factory->uuid1 = Uuid::fromString('177ef0d8-6630-11ea-b69a-0242ac130003'); + $this->assertSame('2020-03-14 20:12:12', $myObj->tellTime()); + + $factory->uuid1 = Uuid::fromString('13814000-1dd2-11b2-9669-00007ffffffe'); + $this->assertSame('1970-01-01 00:00:00', $myObj->tellTime()); + } + +.. attention:: + + The factory is a static property on the Uuid class. By replacing it like + this, all uses of the Uuid class after this point will continue to use the + new factory. This is why we must run the test in a separate process. + Otherwise, this could cause other tests to fail. + + Running tests in separate processes can significantly slow down your tests, + so try to use this technique sparingly, and if possible, pass your + dependencies to your objects, rather than creating (or fetching them) from + within. This makes testing easier. + + +.. _testing.mock: + +Mocking UuidInterface +--------------------- + +Another technique for testing with UUIDs is to mock +:php:interface:`UuidInterface `. + +Consider a method that accepts a UuidInterface. + +.. code-block:: php + + public function tellTime(UuidInterface $uuid): string + { + return $uuid->getDateTime()->format('Y-m-d H:i:s'); + } + +We can mock UuidInterface, passing that mocked value into this method. Then, we +can make assertions about what methods were called on the mock object. In the +following example test, we don't care whether the return value matches an +actual date format. What we care about is that the methods on the UuidInterface +object were called. + +.. code-block:: php + + public function testTellTime(): void + { + $dateTime = Mockery::mock(DateTime::class); + $dateTime->expects()->format('Y-m-d H:i:s')->andReturn('a test date'); + + $uuid = Mockery::mock(UuidInterface::class, [ + 'getDateTime' => $dateTime, + ]); + + $myObj = new MyClass(); + + $this->assertSame('a test date', $myObj->tellTime($uuid)); + } + +.. note:: + + One of my favorite mocking libraries is `Mockery`_, so that's what I use in + these examples. However, other mocking libraries exist, and PHPUnit provides + built-in mocking capabilities. + + +.. _mock object: https://en.wikipedia.org/wiki/Mock_object +.. _PHPUnit: https://phpunit.de +.. _Mockery: https://github.com/mockery/mockery diff --git a/docs/upgrading/2-to-3.rst b/docs/upgrading/2-to-3.rst index b0817d2..2c64fa3 100644 --- a/docs/upgrading/2-to-3.rst +++ b/docs/upgrading/2-to-3.rst @@ -1,6 +1,8 @@ -====================== -ramsey/uuid 2.x to 3.x -====================== +.. _upgrading.2-to-3: + +============== +Version 2 to 3 +============== While we have made significant internal changes to the library, we have made every effort to ensure a seamless upgrade path from the 2.x series of this diff --git a/docs/upgrading/3-to-4.rst b/docs/upgrading/3-to-4.rst index 1c53c67..d49c33b 100644 --- a/docs/upgrading/3-to-4.rst +++ b/docs/upgrading/3-to-4.rst @@ -1,3 +1,476 @@ -====================== -ramsey/uuid 3.x to 4.x -====================== +.. _upgrading.3-to-4: + +============== +Version 3 to 4 +============== + +I've made great efforts to ensure that the upgrade experience for most will be +seamless and uneventful. However, no matter the degree to which you use +ramsey/uuid (customized or unchanged), there are a number of things to be aware +of as you upgrade your code to use version 4. + +.. tip:: + + These are the changes that are most likely to affect you. For a full list of + changes, take a look at the `4.0.0 changelog`_. + + +.. _upgrading.3-to-4.new: + +What's New? +########### + +There are a lot of new features in ramsey/uuid! Here are a few of them: + +* Support :ref:`version 6 UUIDs `. +* Support :ref:`version 2 (DCE Security) UUIDs `. +* Add classes to represent each version of RFC 4122 UUID. When generating new + UUIDs or creating UUIDs from existing strings, bytes, or integers, if the UUID + is an RFC 4122 variant, one of these instances will be returned: + + * :php:class:`Rfc4122\\UuidV1 ` + * :php:class:`Rfc4122\\UuidV2 ` + * :php:class:`Rfc4122\\UuidV3 ` + * :php:class:`Rfc4122\\UuidV4 ` + * :php:class:`Rfc4122\\UuidV5 ` + * Rfc4122\\NilUuid + +* Add classes to represent version 6 UUIDs, GUIDs, and nonstandard + (non-RFC 4122 variant) UUIDs: + + * :php:class:`Nonstandard\\UuidV6 ` + * :php:class:`Nonstandard\\Uuid ` + * :php:class:`Guid\\Guid ` + +* Add :php:meth:`Uuid::fromDateTime() ` to + create version 1 UUIDs from instances of DateTimeInterface. + + +.. _upgrading.3-to-4.changed: + +What's Changed? +############### + +.. attention:: + + ramsey/uuid version 4 requires PHP 7.2 or later. + +Quite a bit has changed, but much remains familiar. Unless you've changed the +behavior of ramsey/uuid through custom codecs, providers, generators, etc., the +standard functionality and API found in version 3 will not differ much. + +.. rubric:: Here are the highlights: + +* ramsey/uuid now works on 32-bit and 64-bit systems, with no degradation in + functionality! All Degraded\* classes are deprecated and no longer used; + they'll go away in ramsey/uuid version 5. +* Pay attention to the :ref:`return types for the static methods + ` on the :php:class:`Uuid ` + class. They've changed slightly, but this won't affect you if your type hints + use :php:interface:`UuidInterface `. +* The :ref:`return types for three methods ` + defined on :php:interface:`UuidInterface ` have + changed, breaking backward compatibility. **Take note, and update your code.** +* :ref:`There are a number of deprecations. ` + These shouldn't affect you now, but please take a look at the recommendations + and update your code soon. These will go away in ramsey/uuid version 5. +* ramsey/uuid now :ref:`throws custom exceptions for everything + `. The exception UnsatisfiedDependencyException no + longer exists. +* If you customize ramsey/uuid at all by implementing the interfaces, take a + look at the :ref:`interface ` and + :ref:`constructor ` changes and update your + code. + + +.. _upgrading.3-to-4.static-methods: + +Uuid Static Methods +################### + +All the static methods on the :php:class:`Uuid ` class +continue to work as they did in version 3, with this slight change: **they now +return more-specific types**, all of which implement the new interface +:php:interface:`Rfc4122\\UuidInterface `, +which implements the familiar interface :php:interface:`UuidInterface +`. + +If your type hints are for :php:interface:`UuidInterface +`, then you should not require any changes. + +.. list-table:: Return types for Uuid static methods + :align: center + :header-rows: 1 + + * - Method + - 3.x Returned + - 4.x Returns + * - :php:meth:`Uuid::uuid1() ` + - :php:class:`Uuid ` + - :php:class:`Rfc4122\\UuidV1 ` + * - :php:meth:`Uuid::uuid3() ` + - :php:class:`Uuid ` + - :php:class:`Rfc4122\\UuidV3 ` + * - :php:meth:`Uuid::uuid4() ` + - :php:class:`Uuid ` + - :php:class:`Rfc4122\\UuidV4 ` + * - :php:meth:`Uuid::uuid5() ` + - :php:class:`Uuid ` + - :php:class:`Rfc4122\\UuidV5 ` + +:php:meth:`Uuid::fromString() `, +:php:meth:`Uuid::fromBytes() `, and +:php:meth:`Uuid::fromInteger() ` all return +an appropriate more-specific type, based on the input value. If the input value +is a version 1 UUID, for example, the return type will be an +:php:class:`Rfc4122\\UuidV1 `. If the input looks +like a UUID or is a 128-bit number, but it doesn't validate as an RFC 4122 UUID, +the return type will be a :php:class:`Nonstandard\\Uuid +`. These return types implement +:php:interface:`UuidInterface `. If using this as +a type hint, you shouldn't need to make any changes. + + +.. _upgrading.3-to-4.return-types: + +Changed Return Types +#################### + +The following :php:interface:`UuidInterface ` +method return types have changed in version 4, and you will need to update your +code, if you use these methods. + +.. list-table:: Changed UuidInterface method return types + :widths: 40 30 30 + :align: center + :header-rows: 1 + + * - Method + - 3.x Returned + - 4.x Returns + * - :php:meth:`UuidInterface::getFields() ` + - ``array`` + - :php:class:`Rfc4122\\FieldsInterface ` + * - :php:meth:`UuidInterface::getHex() ` + - ``string`` + - :php:class:`Type\\Hexadecimal ` + * - :php:meth:`UuidInterface::getInteger() ` + - ``mixed`` [#f1]_ + - :php:class:`Type\\Integer ` + + +.. _upgrading.3-to-4.deprecations: + +Deprecations +############ + +.. _upgrading.3-to-4.deprecations.uuidinterface: + +UuidInterface +------------- + +The following :php:interface:`UuidInterface ` +methods are deprecated, but upgrading to version 4 should not cause any problems +if using these methods. You are encouraged to update your code according to the +recommendations, though, since these methods will go away in version 5. + +.. list-table:: Deprecated UuidInterface methods + :widths: 30 70 + :align: center + :header-rows: 1 + + * - Deprecated Method + - Update To + * - ``getDateTime()`` + - Use ``getDateTime()`` on :php:meth:`UuidV1 + `, :php:meth:`UuidV2 + `, or :php:meth:`UuidV6 + ` + * - ``getClockSeqHiAndReservedHex()`` + - :php:meth:`getFields()->getClockSeqHiAndReserved()->toString() ` + * - ``getClockSeqLowHex()`` + - :php:meth:`getFields()->getClockSeqLow()->toString() ` + * - ``getClockSequenceHex()`` + - :php:meth:`getFields()->getClockSeq()->toString() ` + * - ``getFieldsHex()`` + - :php:meth:`getFields() ` [#f2]_ + * - ``getLeastSignificantBitsHex()`` + - ``substr($uuid->getHex()->toString(), 0, 16)`` + * - ``getMostSignificantBitsHex()`` + - ``substr($uuid->getHex()->toString(), 16)`` + * - ``getNodeHex()`` + - :php:meth:`getFields()->getNode()->toString() ` + * - ``getNumberConverter()`` + - This method has no replacement; plan accordingly. + * - ``getTimeHiAndVersionHex()`` + - :php:meth:`getFields()->getTimeHiAndVersion()->toString() ` + * - ``getTimeLowHex()`` + - :php:meth:`getFields()->getTimeLow()->toString() ` + * - ``getTimeMidHex()`` + - :php:meth:`getFields()->getTimeMid()->toString() ` + * - ``getTimestampHex()`` + - :php:meth:`getFields()->getTimestamp()->toString() ` + * - ``getUrn()`` + - :php:meth:`Ramsey\\Uuid\\Rfc4122\\UuidInterface::getUrn` + * - ``getVariant()`` + - :php:meth:`getFields()->getVariant() ` + * - ``getVersion()`` + - :php:meth:`getFields()->getVersion() ` + +.. _upgrading.3-to-4.deprecations.uuid: + +Uuid +---- + +:php:class:`Uuid ` as an instantiable class is deprecated. +In ramsey/uuid version 5, its constructor will be ``private``, and the class +will be ``final``. For more information, see :ref:`faq.final` + +.. note:: + + :php:class:`Uuid ` is being replaced by more-specific + concrete classes, such as: + + * :php:class:`Rfc4122\\UuidV1 ` + * :php:class:`Rfc4122\\UuidV3 ` + * :php:class:`Rfc4122\\UuidV4 ` + * :php:class:`Rfc4122\\UuidV5 ` + * :php:class:`Nonstandard\\Uuid ` + + However, the :php:class:`Uuid ` class isn't going away. + It will still hold common constants and static methods. + +* ``Uuid::UUID_TYPE_IDENTIFIER`` is deprecated. Use + ``Uuid::UUID_TYPE_DCE_SECURITY`` instead. +* ``Uuid::VALID_PATTERN`` is deprecated. Use the following instead: + + .. code-block:: php + + use Ramsey\Uuid\Validator\GenericValidator; + use Ramsey\Uuid\Rfc4122\Validator as Rfc4122Validator; + + $genericPattern = (new GenericValidator())->getPattern(); + $rfc4122Pattern = (new Rfc4122Validator())->getPattern(); + +The following :php:class:`Uuid ` methods are deprecated. If +using these methods, you shouldn't have any problems on version 4, but you are +encouraged to update your code, since they will go away in version 5. + +* ``getClockSeqHiAndReserved()`` +* ``getClockSeqLow()`` +* ``getClockSequence()`` +* ``getLeastSignificantBits()`` +* ``getMostSignificantBits()`` +* ``getNode()`` +* ``getTimeHiAndVersion()`` +* ``getTimeLow()`` +* ``getTimeMid()`` +* ``getTimestamp()`` + +.. hint:: + + There are no direct replacements for these methods. In ramsey/uuid version + 3, they returned ``int`` or Moontoast\\Math\\BigNumber values, depending + on the environment. To update your code, you should use the recommended + alternates listed in :ref:`Deprecations: UuidInterface + `, combined with the + arbitrary-precision mathematics library of your choice (e.g., `brick/math`_, + `gmp`_, `bcmath`_, etc.). + + .. code-block:: php + :caption: Using brick/math to convert a node to a string integer + + use Brick\Math\BigInteger; + + $node = BigInteger::fromBase($uuid->getFields()->getNode()->toString(), 16); + + +.. _upgrading.3-to-4.interfaces: + +Interface Changes +################# + +For those who customize ramsey/uuid by implementing the interfaces provided, +there are a few breaking changes to note. + +.. hint:: + + Most existing methods on interfaces have type hints added to them. If you + implement any interfaces, please be aware of this and update your classes. + +UuidInterface +------------- + +.. list-table:: + :widths: 25 75 + :align: center + :header-rows: 1 + + * - Method + - Description + * - :php:meth:`__toString() ` + - New method; returns ``string`` + * - :php:meth:`getDateTime() ` + - Deprecated; now returns `DateTimeInterface`_ + * - :php:meth:`getFields() ` + - Used to return ``array``; now returns :php:class:`Rfc4122\\FieldsInterface ` + * - :php:meth:`getHex() ` + - Used to return ``string``; now returns :php:class:`Type\\Hexadecimal ` + * - :php:meth:`getInteger() ` + - New method; returns :php:class:`Type\\Integer ` + +UuidFactoryInterface +-------------------- + +.. list-table:: + :widths: 25 75 + :align: center + :header-rows: 1 + + * - Method + - Description + * - :php:meth:`uuid2() ` + - New method; returns :php:class:`Rfc4122\\UuidV2 ` + * - :php:meth:`uuid6() ` + - New method; returns :php:class:`Nonstandard\\UuidV6 ` + * - :php:meth:`fromDateTime() ` + - New method; returns :php:class:`UuidInterface ` + * - :php:meth:`fromInteger() ` + - Changed to accept only strings + * - :php:meth:`getValidator() ` + - New method; returns :php:class:`UuidInterface ` + +Builder\\UuidBuilderInterface +----------------------------- + +.. list-table:: + :widths: 25 75 + :align: center + :header-rows: 1 + + * - Method + - Description + * - ``build()`` + - Second parameter used to accept ``array $fields``; now accepts ``string $bytes`` + +Converter\\TimeConverterInterface +--------------------------------- + +.. list-table:: + :widths: 25 75 + :align: center + :header-rows: 1 + + * - Method + - Description + * - ``calculateTime()`` + - Used to return ``string[]``; now returns :php:class:`Type\\Hexadecimal ` + * - ``convertTime()`` + - New method; returns :php:class:`Type\\Time ` + +Provider\\TimeProviderInterface +--------------------------------- + +.. list-table:: + :widths: 25 75 + :align: center + :header-rows: 1 + + * - Method + - Description + * - ``currentTime()`` + - Method removed from interface; use ``getTime()`` instead + * - ``getTime()`` + - New method; returns :php:class:`Type\\Time ` + +Provider\\NodeProviderInterface +--------------------------------- + +.. list-table:: + :widths: 25 75 + :align: center + :header-rows: 1 + + * - Method + - Description + * - ``getNode()`` + - Used to return ``string|false|null``; now returns :php:class:`Type\\Hexadecimal ` + + +.. _upgrading.3-to-4.constructors: + +Constructor Changes +################### + +There are a handful of constructor changes that might affect your use of +ramsey/uuid, especially if you customize the library. + +Uuid +---- + +The constructor for :php:class:`Ramsey\\Uuid\\Uuid` is deprecated. However, +there are a few changes to it that might affect your use of this class. + +The first constructor parameter used to be ``array $fields`` and is now +:php:interface:`Rfc4122\\FieldsInterface $fields +`. + +``Converter\TimeConverterInterface $timeConverter`` is required as a new fourth +parameter. + +Builder\\DefaultUuidBuilder +--------------------------- + +While Builder\\DefaultUuidBuilder is deprecated, it now inherits from +Rfc4122\\UuidBuilder, which requires ``Converter\TimeConverterInterface +$timeConverter`` as its second constructor argument. + +Provider\\Node\\FallbackNodeProvider +------------------------------------ + +Provider\\Node\\FallbackNodeProvider now requires a +Provider\\Node\\NodeProviderCollection as its constructor parameter. This +behaves like a typed array. + +.. code-block:: + + use MyPackage\MyCustomNodeProvider; + use Ramsey\Uuid\Provider\Node\FallbackNodeProvider; + use Ramsey\Uuid\Provider\Node\NodeProviderCollection; + use Ramsey\Uuid\Provider\Node\RandomNodeProvider; + use Ramsey\Uuid\Provider\Node\SystemNodeProvider; + + $collection = new NodeProviderCollection(); + $collection[] = new MyCustomNodeProvider(); + $collection[] = new SystemNodeProvider(); + $collection[] = new RandomNodeProvider(); + + $provider = new FallbackNodeProvider($collection); + +Provider\\Time\\FixedTimeProvider +--------------------------------- + +The constructor for Provider\\Time\\FixedTimeProvider no longer accepts an +array. It accepts :php:class:`Type\\Time ` instances. + + +------------------------------------------------------------------------------- + +.. rubric:: Footnotes + +.. [#f1] This ``mixed`` return type could have been an ``int``, ``string``, or + Moontoast\\Math\\BigNumber. In version 4, ramsey/uuid cleans this up for + the sake of consistency. + +.. [#f2] The :php:meth:`getFields() ` + method returns a :php:class:`Type\\Hexadecimal ` + instance; you will need to construct an array if you wish to match the + return value of the deprecated ``getFieldsHex()`` method. + + +.. _version 6 UUIDs: http://gh.peabody.io/uuidv6/ +.. _4.0.0 changelog: https://github.com/ramsey/uuid/releases/tag/4.0.0 +.. _brick/math: https://github.com/brick/math +.. _gmp: https://www.php.net/gmp +.. _bcmath: https://www.php.net/bcmath +.. _DateTimeInterface: https://www.php.net/datetimeinterface diff --git a/src/FeatureSet.php b/src/FeatureSet.php index a7ed419..4531a6d 100644 --- a/src/FeatureSet.php +++ b/src/FeatureSet.php @@ -273,6 +273,10 @@ class FeatureSet $this->calculator = $calculator; $this->numberConverter = $this->buildNumberConverter($calculator); $this->timeConverter = $this->buildTimeConverter($calculator); + + if (isset($this->timeProvider)) { + $this->timeGenerator = $this->buildTimeGenerator($this->timeProvider); + } } /** diff --git a/src/Math/CalculatorInterface.php b/src/Math/CalculatorInterface.php index f2dbd13..f03645d 100644 --- a/src/Math/CalculatorInterface.php +++ b/src/Math/CalculatorInterface.php @@ -61,7 +61,7 @@ interface CalculatorInterface * @param int $roundingMode The RoundingMode constant to use for this operation * @param int $scale The scale to use for this operation * @param NumberInterface $dividend The integer to be divided - * @param NumberInterface ...$divisors + * @param NumberInterface ...$divisors The integers to divide $dividend by, in * the order in which the division operations should take place * (left-to-right) * diff --git a/src/Math/RoundingMode.php b/src/Math/RoundingMode.php index 82f1cb7..e710270 100644 --- a/src/Math/RoundingMode.php +++ b/src/Math/RoundingMode.php @@ -56,10 +56,6 @@ final class RoundingMode /** * Asserts that the requested operation has an exact result, hence no * rounding is necessary. - * - * If this rounding mode is specified on an operation that yields a result - * that cannot be represented at the requested scale, a - * RoundingNecessaryException is thrown. */ public const UNNECESSARY = 0; diff --git a/src/Rfc4122/Validator.php b/src/Rfc4122/Validator.php index 97cdb7e..7dcf078 100644 --- a/src/Rfc4122/Validator.php +++ b/src/Rfc4122/Validator.php @@ -22,6 +22,8 @@ use function str_replace; /** * Rfc4122\Validator validates strings as UUIDs of the RFC 4122 variant + * + * @psalm-immutable */ final class Validator implements ValidatorInterface { @@ -29,7 +31,6 @@ final class Validator implements ValidatorInterface . '[1-5]{1}[0-9A-Fa-f]{3}-[ABab89]{1}[0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$'; /** - * @psalm-pure * @psalm-return non-empty-string * @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty * @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty @@ -39,9 +40,6 @@ final class Validator implements ValidatorInterface return self::VALID_PATTERN; } - /** - * @psalm-pure - */ public function validate(string $uuid): bool { $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); diff --git a/src/Validator/GenericValidator.php b/src/Validator/GenericValidator.php index 84fc645..f6a6010 100644 --- a/src/Validator/GenericValidator.php +++ b/src/Validator/GenericValidator.php @@ -21,6 +21,8 @@ use function str_replace; /** * GenericValidator validates strings as UUIDs of any variant + * + * @psalm-immutable */ final class GenericValidator implements ValidatorInterface { @@ -30,7 +32,6 @@ final class GenericValidator implements ValidatorInterface private 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}$'; /** - * @psalm-pure * @psalm-return non-empty-string * @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty * @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty @@ -40,9 +41,6 @@ final class GenericValidator implements ValidatorInterface return self::VALID_PATTERN; } - /** - * @psalm-pure - */ public function validate(string $uuid): bool { $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); diff --git a/src/Validator/ValidatorInterface.php b/src/Validator/ValidatorInterface.php index ef813c2..3d4bd6f 100644 --- a/src/Validator/ValidatorInterface.php +++ b/src/Validator/ValidatorInterface.php @@ -16,6 +16,8 @@ namespace Ramsey\Uuid\Validator; /** * A validator validates a string as a proper UUID + * + * @psalm-immutable */ interface ValidatorInterface { @@ -24,7 +26,6 @@ interface ValidatorInterface * * @return string The regular expression pattern this validator uses * - * @psalm-pure * @psalm-return non-empty-string */ public function getPattern(): string; @@ -35,8 +36,6 @@ interface ValidatorInterface * @param string $uuid The string to validate as a UUID * * @return bool True if the string is a valid UUID, false otherwise - * - * @psalm-pure */ public function validate(string $uuid): bool; }