From ffc5e32740a0e4d848dbbb47b4d5f0e9f41a9806 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sun, 8 Mar 2020 22:15:48 -0500 Subject: [PATCH] [ci skip] Complete the "customization" portion of the documentation --- docs/customize.rst | 26 +++++ docs/customize/ordered-time-codec.rst | 79 ++++++++++++++ docs/customize/timestamp-first-comb-codec.rst | 60 +++++++++++ docs/database.rst | 2 +- docs/reference.rst | 1 + docs/reference/uuid.rst | 9 +- docs/reference/uuidfactoryinterface.rst | 102 ++++++++++++++++++ 7 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 docs/reference/uuidfactoryinterface.rst diff --git a/docs/customize.rst b/docs/customize.rst index cafd884..637c3c9 100644 --- a/docs/customize.rst +++ b/docs/customize.rst @@ -6,6 +6,32 @@ Customization .. toctree:: :titlesonly: + :hidden: customize/ordered-time-codec customize/timestamp-first-comb-codec + +ramsey/uuid offers a variety of ways to modify the standard behavior of the +library through dependency injection. Using `UuidFactory`_, `FeatureSet`_, and +:php:meth:`Uuid::setFactory() `, you are able +to replace just about any `codec`_, `builder`_, `converter`_, `provider`_, +`generator`_, and more. + +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`. + +Timestamp-first COMB Codec + The timestamp-first COMB codec replaces part of a version 4, random UUID + with a timestamp, so that the UUID becomes monotonically increasing. To + learn more, see :ref:`customize.timestamp-first-comb-codec`. + + +.. _UuidFactory: https://github.com/ramsey/uuid/blob/master/src/UuidFactory.php +.. _FeatureSet: https://github.com/ramsey/uuid/blob/master/src/FeatureSet.php +.. _codec: https://github.com/ramsey/uuid/tree/master/src/Codec +.. _builder: https://github.com/ramsey/uuid/tree/master/src/Builder +.. _converter: https://github.com/ramsey/uuid/tree/master/src/Converter +.. _provider: https://github.com/ramsey/uuid/tree/master/src/Provider +.. _generator: https://github.com/ramsey/uuid/tree/master/src/Generator diff --git a/docs/customize/ordered-time-codec.rst b/docs/customize/ordered-time-codec.rst index ce3a75d..bad166f 100644 --- a/docs/customize/ordered-time-codec.rst +++ b/docs/customize/ordered-time-codec.rst @@ -3,3 +3,82 @@ ================== 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. + +UUIDs arrange their bytes according to the standard recommended by `RFC 4122`_. +Unfortunately, this means the bytes aren't in an arrangement that supports +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. + +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 +*monotonically increasing*, each one coming after the previously-created one, in +a proper sort order. + +.. code-block:: php + :caption: Use the ordered-time codec to generate a version 1 UUID + :name: customize.ordered-time-codec-example + + use Ramsey\Uuid\Codec\OrderedTimeCodec; + use Ramsey\Uuid\UuidFactory; + + $factory = new UuidFactory(); + $codec = new OrderedTimeCodec($factory->getUuidBuilder()); + + $factory->setCodec($codec); + + $orderedTimeUuid = $factory->uuid1(); + + printf( + "UUID: %s\nVersion: %d\nDate: %s\nNode: %s\nBytes: %s\n", + $orderedTimeUuid->toString(), + $orderedTimeUuid->getFields()->getVersion(), + $orderedTimeUuid->getDateTime()->format('r'), + $orderedTimeUuid->getFields()->getNode()->toString(), + bin2hex($orderedTimeUuid->getBytes()) + ); + +This will use the ordered-time codec to generate a version 1 UUID and will print +out details about the UUID similar to these: + +.. code-block:: text + + UUID: 593200aa-61ae-11ea-bbf2-0242ac130003 + Version: 1 + Date: Mon, 09 Mar 2020 02:33:23 +0000 + Node: 0242ac130003 + Bytes: 11ea61ae593200aabbf20242ac130003 + +.. attention:: + + Only the byte representation is rearranged. The string representation + follows the format of a standard version 1 UUID. This means only the byte + representation of an ordered-time codec encoded UUID may be used for + sorting, such as with database results. + + To store the byte representation to a database field, see + :ref:`database.bytes`. + +.. hint:: + + If you use this codec and store the bytes of the UUID to the database, as + recommended above, you will need to use this codec to decode the bytes, as + well. Otherwise, the UUID string value will be incorrect. + + .. code-block:: php + + // Using a factory configured with the OrderedTimeCodec, as shown above. + $orderedTimeUuid = $factory->fromBytes($bytes); + + +.. _RFC 4122: https://tools.ietf.org/html/rfc4122 +.. _Storing UUID Values in MySQL: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/ diff --git a/docs/customize/timestamp-first-comb-codec.rst b/docs/customize/timestamp-first-comb-codec.rst index 909395d..00f3377 100644 --- a/docs/customize/timestamp-first-comb-codec.rst +++ b/docs/customize/timestamp-first-comb-codec.rst @@ -3,3 +3,63 @@ ========================== Timestamp-first COMB Codec ========================== + +: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 +be rearranged, like with the :ref:`ordered-time codec +`. In 2002, Jimmy Nilsson recognized this problem +with random UUIDs and proposed a solution he called "COMBs" (see "`The Cost of +GUIDs as Primary Keys`_"). + +So-called because they *combine* random bytes with a timestamp, the +timestamp-first COMB codec replaces the first 48 bits of a version 4, random +UUID with a Unix timestamp and microseconds, creating an identifier that can be +sorted by creation time. These UUIDs are *monotonically increasing*, each one +coming after the previously-created one, in a proper sort order. + +.. code-block:: php + :caption: Use the timestamp-first COMB codec to generate a version 4 UUID + :name: customize.timestamp-first-comb-codec-example + + use Ramsey\Uuid\Codec\TimestampFirstCombCodec; + use Ramsey\Uuid\Generator\CombGenerator; + use Ramsey\Uuid\UuidFactory; + + $factory = new UuidFactory(); + $codec = new TimestampFirstCombCodec($factory->getUuidBuilder()); + + $factory->setCodec($codec); + + $factory->setRandomGenerator(new CombGenerator( + $factory->getRandomGenerator(), + $factory->getNumberConverter() + )); + + $timestampFirstComb = $factory->uuid4(); + + printf( + "UUID: %s\nVersion: %d\nBytes: %s\n", + $timestampFirstComb->toString(), + $timestampFirstComb->getFields()->getVersion(), + bin2hex($timestampFirstComb->getBytes()) + ); + +This will use the timestamp-first COMB codec to generate a version 4 UUID with +the timestamp replacing the first 48 bits and will print out details about the +UUID similar to these: + +.. code-block:: text + + UUID: 9009ebcc-cd99-4b5f-90cf-9155607d2de9 + Version: 4 + Bytes: 9009ebcccd994b5f90cf9155607d2de9 + +Note that the bytes are in the same order as the string representation. Unlike +the :ref:`ordered-time codec `, the +timestamp-first COMB codec affects both the string representation and the byte +representation. This means either the string UUID or the bytes may be stored to +a datastore and sorted. To learn more, see :ref:`database`. + + +.. _The Cost of GUIDs as Primary Keys: https://www.informit.com/articles/printerfriendly/25862 diff --git a/docs/database.rst b/docs/database.rst index 517e7e1..d939be5 100644 --- a/docs/database.rst +++ b/docs/database.rst @@ -245,7 +245,7 @@ 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 would take the place of ordered time UUIDs. + new version of UUID that take the place of ordered time UUIDs. .. _ramsey/uuid-doctrine: https://github.com/ramsey/uuid-doctrine diff --git a/docs/reference.rst b/docs/reference.rst index 19bade5..fc02b7b 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -22,6 +22,7 @@ Reference reference/guid-guid reference/nonstandard-fields reference/nonstandard-uuid + reference/uuidfactoryinterface reference/types reference/exceptions reference/helper diff --git a/docs/reference/uuid.rst b/docs/reference/uuid.rst index a835208..f3c2f32 100644 --- a/docs/reference/uuid.rst +++ b/docs/reference/uuid.rst @@ -174,11 +174,18 @@ the ramsey/uuid library. .. php:staticmethod:: isValid($uuid) - Validates the string standard representation of a UUID + Validates the string standard representation of a UUID. :param string $uuid: The string standard representation of a UUID :returntype: ``bool`` + .. php:staticmethod:: setFactory($factory) + + Sets the factory used to create UUIDs. + + :param Ramsey\\Uuid\\UuidFactoryInterface $factory: A UUID factory to use for all UUID generation + :returntype: void + .. _ISO object identifier (OID): http://www.oid-info.com .. _X.500: https://en.wikipedia.org/wiki/X.500 diff --git a/docs/reference/uuidfactoryinterface.rst b/docs/reference/uuidfactoryinterface.rst new file mode 100644 index 0000000..842f71d --- /dev/null +++ b/docs/reference/uuidfactoryinterface.rst @@ -0,0 +1,102 @@ +.. _reference.uuidfactoryinterface: + +==================== +UuidFactoryInterface +==================== + +.. php:namespace:: Ramsey\Uuid + +.. php:interface:: UuidFactoryInterface + + Represents a UUID factory. + + .. php:method:: getValidator() + + :returntype: Ramsey\\Uuid\\Validator\\ValidatorInterface + + .. php:method:: uuid1([$node[, $clockSeq]]) + + Generates a version 1, time-based 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 + :returns: A version 1 UUID + :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV1 + + .. php:method:: uuid2($localDomain[, $localIdentifier[, $node[, $clockSeq]]]) + + Generates a version 2, DCE Security UUID. See :ref:`rfc4122.version2`. + + :param int $localDomain: The local domain to use (one of :php:const:`Uuid::DCE_DOMAIN_PERSON`, :php:const:`Uuid::DCE_DOMAIN_GROUP`, or :php:const:`Uuid::DCE_DOMAIN_ORG`) + :param Ramsey\\Uuid\\Type\\Integer|null $localIdentifier: A local identifier for the domain (defaults to system UID or GID for *person* or *group*) + :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 2 UUID + :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV2 + + .. php:method:: uuid3($ns, $name) + + Generates a version 3, name-based (MD5) UUID. See :ref:`rfc4122.version3`. + + :param Ramsey\\Uuid\\UuidInterface|string $ns: The namespace for this identifier + :param string $name: The name from which to generate an identifier + :returns: A version 3 UUID + :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV3 + + .. php:method:: uuid4() + + Generates a version 4, random UUID. See :ref:`rfc4122.version4`. + + :returns: A version 4 UUID + :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV4 + + .. php:method:: uuid5($ns, $name) + + Generates a version 5, name-based (SHA-1) UUID. See :ref:`rfc4122.version5`. + + :param Ramsey\\Uuid\\UuidInterface|string $ns: The namespace for this identifier + :param string $name: The name from which to generate an identifier + :returns: A version 5 UUID + :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV5 + + .. php:method:: uuid6([$node[, $clockSeq]]) + + Generates a version 6, ordered-time UUID. See :ref:`nonstandard.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 + + .. php:method:: fromString($uuid) + + Creates an instance of UuidInterface from the string standard + representation. + + :param string $uuid: The string standard representation of a UUID + :returntype: Ramsey\\Uuid\\UuidInterface + + .. php:method:: fromBytes($bytes) + + Creates an instance of UuidInterface from a 16-byte string. + + :param string $bytes: A 16-byte binary string representation of a UUID + :returntype: Ramsey\\Uuid\\UuidInterface + + .. php:method:: fromInteger($integer) + + Creates an instance of UuidInterface from a 128-bit string integer. + + :param string $integer: A 128-bit string integer representation of a UUID + :returntype: Ramsey\\Uuid\\UuidInterface + + .. php:method:: fromDateTime($dateTime[, $node[, $clockSeq]]) + + Creates a version 1 UUID instance from a `DateTimeInterface + `_ instance. + + :param DateTimeInterface $dateTime: The date from which to create the UUID instance + :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 1 UUID + :returntype: Ramsey\\Uuid\\Rfc4122\\UuidV1