Skip to content

Add support for UUID validation using ramsey/uuid to support all UUID… #1542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: 2.4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@
"phpunit/phpunit": "^9.6",
"psr/http-message": "^1.0",
"respect/coding-standard": "^4.0",
"squizlabs/php_codesniffer": "^3.7"
"squizlabs/php_codesniffer": "^3.7",
"ramsey/uuid": "^4"
},
"suggest": {
"ext-bcmath": "Arbitrary Precision Mathematics",
"ext-fileinfo": "File Information",
"ext-mbstring": "Multibyte String Functions",
"egulias/email-validator": "Improves the Email rule if available",
"giggsey/libphonenumber-for-php-lite": "Enables the phone rule if available"
"giggsey/libphonenumber-for-php-lite": "Enables the phone rule if available",
"ramsey/uuid": "Improves UUID checking if available"
},
"autoload": {
"psr-4": {
Expand Down
16 changes: 16 additions & 0 deletions docs/rules/Uuid.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- `Uuid()`
- `Uuid(int $version)`
- `Uuid(?int $version, ?bool $useRamseyUuid)`

Validates whether the input is a valid UUID. It also supports validation of
specific versions 1, 3, 4 and 5.
Expand All @@ -13,6 +14,21 @@ v::uuid(1)->isValid('eb3115e5-bd16-4939-ab12-2b95745a30f3'); // false
v::uuid(4)->isValid('eb3115e5-bd16-4939-ab12-2b95745a30f3'); // true
```

Optionally, you are able to use ramsey/uuid library to support validation
of all UUID versions 1 to 8, This will be automatically enabled if ramsey/uuid
is detected but can be manually disabled to revert to the original behavior.

if ramsey/uuid is loaded
```php
v::uuid()->isValid('Hello World!'); // false
v::uuid()->isValid('eb3115e5-bd16-4939-ab12-2b95745a30f3'); // true
v::uuid(1)->isValid('eb3115e5-bd16-4939-ab12-2b95745a30f3'); // false
v::uuid(4)->isValid('eb3115e5-bd16-4939-ab12-2b95745a30f3'); // true
v::uuid(8)->isValid('00112233-4455-8677-8899-aabbccddeeff'); // true
v::uuid(8, false)->isValid('00112233-4455-8677-8899-aabbccddeeff'); // false <-- same UUID as above, but with ramsey/uuid disabled
v::uuid(4)->isValid(new \Ramsey\Uuid\Uuid::fromString('eb3115e5-bd16-4939-ab12-2b95745a30f3')); // true
```

## Categorization

- Strings
Expand Down
2 changes: 1 addition & 1 deletion library/ChainedValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ public function uppercase(): ChainedValidator;

public function url(): ChainedValidator;

public function uuid(?int $version = null): ChainedValidator;
public function uuid(?int $version = null, ?bool $useRamseyUuid = null): ChainedValidator;

public function version(): ChainedValidator;

Expand Down
61 changes: 57 additions & 4 deletions library/Rules/Uuid.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@

namespace Respect\Validation\Rules;

use Ramsey\Uuid\Uuid as RamseyUuid;
use Ramsey\Uuid\UuidInterface;
use Respect\Validation\Exceptions\ComponentException;

use function class_exists;
use function is_string;
use function preg_match;
use function sprintf;
Expand All @@ -34,18 +37,39 @@ final class Uuid extends AbstractRule
/**
* The UUID version to validate for.
*
* @var int|null
*/
private $version;
private ?int $version;

/**
* Whether to use Ramsey/Uuid to validate the UUID.
*
*/
private bool $useRamseyUuid = false;

/**
* Whether Ramsey/Uuid is loaded.
*
*/
private static ?bool $ramseyUuidIsLoaded = null;

/**
* Initializes the rule with the desired version.
*
* @throws ComponentException when the version is not valid
*/
public function __construct(?int $version = null)
public function __construct(?int $version = null, ?bool $useRamseyUuid = null)
{
if ($useRamseyUuid && !$this->ramseyUuidIsLoaded()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's really awesome, thank you so much! I would say though, we could aways use RamseyUuid for this rule, we just need to require it to be install. In that case, this branch should be based on main, to be released with the next major version. What do you say?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying not to introduce any BC breaks and allow RamseyUuid to be optional.

But if you are good with making RamseyUuid required, it would clean up the code loads.

I was targeting this at 2.4 so it could be used quicker, has I dont know how far version 3.0 is from release.

I will make the chages to make RamseyUuid a required and clean up the code 😁

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, just looking at the main version, I will create a new version for the main and leave the PR here if you want to merge this into 2.4

throw new ComponentException('Ramsey/Uuid is not installed');
}

$this->useRamseyUuid = $useRamseyUuid ?? $this->ramseyUuidIsLoaded();

if ($version !== null && !$this->isSupportedVersion($version)) {
if ($this->useRamseyUuid) {
throw new ComponentException(sprintf('Only versions 1 to 8 are supported: %d given', $version));
}

throw new ComponentException(sprintf('Only versions 1, 3, 4, and 5 are supported: %d given', $version));
}

Expand All @@ -57,6 +81,26 @@ public function __construct(?int $version = null)
*/
public function validate($input): bool
{
if ($this->useRamseyUuid) {
if (!is_string($input) && !($input instanceof UuidInterface)) {
return false;
}

if (is_string($input) && RamseyUuid::isValid($input)) {
$input = RamseyUuid::fromString($input);
}

if ($input instanceof UuidInterface) {
if ($this->version !== null) {
return $input->getVersion() === $this->version;
}

return $input->getVersion() !== null;
}

return false;
}

if (!is_string($input)) {
return false;
}
Expand All @@ -66,7 +110,7 @@ public function validate($input): bool

private function isSupportedVersion(int $version): bool
{
return $version >= 1 && $version <= 5 && $version !== 2;
return $this->useRamseyUuid ? $version >= 1 && $version <= 8 : $version >= 1 && $version <= 5 && $version !== 2;
}

private function getPattern(): string
Expand All @@ -77,4 +121,13 @@ private function getPattern(): string

return sprintf(self::PATTERN_FORMAT, '[13-5]');
}

private function ramseyUuidIsLoaded(): bool
{
if (self::$ramseyUuidIsLoaded === null) {
self::$ramseyUuidIsLoaded = class_exists(RamseyUuid::class);
}

return self::$ramseyUuidIsLoaded;
}
}
2 changes: 1 addition & 1 deletion library/StaticValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ public static function uppercase(): ChainedValidator;

public static function url(): ChainedValidator;

public static function uuid(?int $version = null): ChainedValidator;
public static function uuid(?int $version = null, ?bool $useRamseyUuid = null): ChainedValidator;

public static function version(): ChainedValidator;

Expand Down
Loading