Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Uid] Add component-specific exception classes #60226

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

Merged
merged 1 commit into from
Apr 17, 2025
Merged
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
20 changes: 11 additions & 9 deletions src/Symfony/Component/Uid/AbstractUid.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Component\Uid;

use Symfony\Component\Uid\Exception\InvalidArgumentException;

/**
* @author Nicolas Grekas <[email protected]>
*/
Expand All @@ -29,41 +31,41 @@ abstract public static function isValid(string $uid): bool;
/**
* Creates an AbstractUid from an identifier represented in any of the supported formats.
*
* @throws \InvalidArgumentException When the passed value is not valid
* @throws InvalidArgumentException When the passed value is not valid
*/
abstract public static function fromString(string $uid): static;

/**
* @throws \InvalidArgumentException When the passed value is not valid
* @throws InvalidArgumentException When the passed value is not valid
*/
public static function fromBinary(string $uid): static
{
if (16 !== \strlen($uid)) {
throw new \InvalidArgumentException('Invalid binary uid provided.');
throw new InvalidArgumentException('Invalid binary uid provided.');
}

return static::fromString($uid);
}

/**
* @throws \InvalidArgumentException When the passed value is not valid
* @throws InvalidArgumentException When the passed value is not valid
*/
public static function fromBase58(string $uid): static
{
if (22 !== \strlen($uid)) {
throw new \InvalidArgumentException('Invalid base-58 uid provided.');
throw new InvalidArgumentException('Invalid base-58 uid provided.');
}

return static::fromString($uid);
}

/**
* @throws \InvalidArgumentException When the passed value is not valid
* @throws InvalidArgumentException When the passed value is not valid
*/
public static function fromBase32(string $uid): static
{
if (26 !== \strlen($uid)) {
throw new \InvalidArgumentException('Invalid base-32 uid provided.');
throw new InvalidArgumentException('Invalid base-32 uid provided.');
}

return static::fromString($uid);
Expand All @@ -72,12 +74,12 @@ public static function fromBase32(string $uid): static
/**
* @param string $uid A valid RFC 9562/4122 uid
*
* @throws \InvalidArgumentException When the passed value is not valid
* @throws InvalidArgumentException When the passed value is not valid
*/
public static function fromRfc4122(string $uid): static
{
if (36 !== \strlen($uid)) {
throw new \InvalidArgumentException('Invalid RFC4122 uid provided.');
throw new InvalidArgumentException('Invalid RFC4122 uid provided.');
}

return static::fromString($uid);
Expand Down
6 changes: 4 additions & 2 deletions src/Symfony/Component/Uid/BinaryUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Component\Uid;

use Symfony\Component\Uid\Exception\InvalidArgumentException;

/**
* @internal
*
Expand Down Expand Up @@ -162,7 +164,7 @@ public static function dateTimeToHex(\DateTimeInterface $time): string
{
if (\PHP_INT_SIZE >= 8) {
if (-self::TIME_OFFSET_INT > $time = (int) $time->format('Uu0')) {
throw new \InvalidArgumentException('The given UUID date cannot be earlier than 1582-10-15.');
throw new InvalidArgumentException('The given UUID date cannot be earlier than 1582-10-15.');
}

return str_pad(dechex(self::TIME_OFFSET_INT + $time), 16, '0', \STR_PAD_LEFT);
Expand All @@ -171,7 +173,7 @@ public static function dateTimeToHex(\DateTimeInterface $time): string
$time = $time->format('Uu0');
$negative = '-' === $time[0];
if ($negative && self::TIME_OFFSET_INT < $time = substr($time, 1)) {
throw new \InvalidArgumentException('The given UUID date cannot be earlier than 1582-10-15.');
throw new InvalidArgumentException('The given UUID date cannot be earlier than 1582-10-15.');
}
$time = self::fromBase($time, self::BASE10);
$time = str_pad($time, 8, "\0", \STR_PAD_LEFT);
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Uid/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

7.3
---

* Add component-specific exception hierarchy

7.2
---

Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Component/Uid/Command/GenerateUuidCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Uid\Exception\LogicException;
use Symfony\Component\Uid\Factory\UuidFactory;
use Symfony\Component\Uid\Uuid;

Expand Down Expand Up @@ -146,7 +147,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$create = function () use ($namespace, $name): Uuid {
try {
$factory = $this->factory->nameBased($namespace);
} catch (\LogicException) {
} catch (LogicException) {
throw new \InvalidArgumentException('Missing namespace: use the "--namespace" option or configure a default namespace in the underlying factory.');
}

Expand Down
16 changes: 16 additions & 0 deletions src/Symfony/Component/Uid/Exception/InvalidArgumentException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Uid\Exception;

class InvalidArgumentException extends \InvalidArgumentException
{
}
Comment on lines +14 to +16
Copy link
Contributor

Choose a reason for hiding this comment

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

@nicolas-grekas , do you think it could contain value?

Copy link
Member

Choose a reason for hiding this comment

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

We generally don't include a value in our InvalidArgumentException exceptions. When such error happens for an error related to an object, this would mean that the exception retains a reference to that object (even if you never call the getter), which would have an impact on GC.

Copy link
Member Author

@nicolas-grekas nicolas-grekas Apr 16, 2025

Choose a reason for hiding this comment

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

What @stof wrote (and where the previous PR blocked IMHO)
So better not to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not a reference shall make the impact on garbage collection, unless it creates a circular reference.

Copy link
Member Author

Choose a reason for hiding this comment

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

Still, not something that makes sense to me.

Copy link
Member Author

@nicolas-grekas nicolas-grekas Apr 17, 2025

Choose a reason for hiding this comment

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

Sure, but it's not the responsibility of the exception to carry this as a standalone value. (the native InvalidArgumentException doesn't carry it if you want an example)

Copy link
Contributor

Choose a reason for hiding this comment

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

It is, and it must have the value inside

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm sorry you feel frustrated about the situation. We made a step in the direction you're aiming for but we don't do the last step for reasons I already shared. You'll have to parse the message for your use case...

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't feel any frustration about anything. I have a big lump of faith down inside of me believing that it is the way to go, and that it should be implemented.

Copy link
Contributor

Choose a reason for hiding this comment

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

@nicolas-grekas , I want you to receive this idea

20 changes: 20 additions & 0 deletions src/Symfony/Component/Uid/Exception/InvalidUlidException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Uid\Exception;

class InvalidUlidException extends InvalidArgumentException
{
public function __construct(string $value)
{
parent::__construct(\sprintf('Invalid ULID: "%s".', $value));
}
}
22 changes: 22 additions & 0 deletions src/Symfony/Component/Uid/Exception/InvalidUuidException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Uid\Exception;

class InvalidUuidException extends InvalidArgumentException
{
public function __construct(
public readonly int $type,
string $value,
Copy link
Contributor

Choose a reason for hiding this comment

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

do you think it'd be possible to make value accessible as well?

actually there'd been discussion regarding this in a previous MR, @fabpot prefers private property and getter

Copy link
Member Author

Choose a reason for hiding this comment

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

private property and getter

I saw that but I think this is still better :)

) {
parent::__construct(\sprintf('Invalid UUID%s: "%s".', $type ? 'v'.$type : '', $value));
}
}
16 changes: 16 additions & 0 deletions src/Symfony/Component/Uid/Exception/LogicException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Uid\Exception;

class LogicException extends \LogicException
{
}
6 changes: 5 additions & 1 deletion src/Symfony/Component/Uid/Factory/UuidFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\Uid\Factory;

use Symfony\Component\Uid\Exception\LogicException;
use Symfony\Component\Uid\Uuid;
use Symfony\Component\Uid\UuidV1;
use Symfony\Component\Uid\UuidV4;
Expand Down Expand Up @@ -67,12 +68,15 @@ public function timeBased(Uuid|string|null $node = null): TimeBasedUuidFactory
return new TimeBasedUuidFactory($this->timeBasedClass, $node);
}

/**
* @throws LogicException When no namespace is defined
*/
public function nameBased(Uuid|string|null $namespace = null): NameBasedUuidFactory
{
$namespace ??= $this->nameBasedNamespace;

if (null === $namespace) {
throw new \LogicException(\sprintf('A namespace should be defined when using "%s()".', __METHOD__));
throw new LogicException(\sprintf('A namespace should be defined when using "%s()".', __METHOD__));
}

return new NameBasedUuidFactory($this->nameBasedClass, $this->getNamespace($namespace));
Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Component/Uid/Tests/Factory/UlidFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Uid\Tests\Factory;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Uid\Exception\InvalidArgumentException;
use Symfony\Component\Uid\Factory\UlidFactory;

final class UlidFactoryTest extends TestCase
Expand All @@ -36,7 +37,7 @@ public function testCreate()

public function testCreateWithInvalidTimestamp()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The timestamp must be positive.');

(new UlidFactory())->create(new \DateTimeImmutable('@-1000'));
Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Component/Uid/Tests/Factory/UuidFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Uid\Tests\Factory;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Uid\Exception\InvalidArgumentException;
use Symfony\Component\Uid\Factory\UuidFactory;
use Symfony\Component\Uid\NilUuid;
use Symfony\Component\Uid\Uuid;
Expand Down Expand Up @@ -81,7 +82,7 @@ public function testCreateTimed()

public function testInvalidCreateTimed()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The given UUID date cannot be earlier than 1582-10-15.');

(new UuidFactory())->timeBased()->create(new \DateTimeImmutable('@-12219292800.001000'));
Expand Down
12 changes: 7 additions & 5 deletions src/Symfony/Component/Uid/Tests/UlidTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
namespace Symfony\Component\Uid\Tests;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Uid\Exception\InvalidArgumentException;
use Symfony\Component\Uid\Exception\InvalidUlidException;
use Symfony\Component\Uid\MaxUlid;
use Symfony\Component\Uid\NilUlid;
use Symfony\Component\Uid\Tests\Fixtures\CustomUlid;
Expand Down Expand Up @@ -41,7 +43,7 @@ public function testGenerate()

public function testWithInvalidUlid()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidUlidException::class);
$this->expectExceptionMessage('Invalid ULID: "this is not a ulid".');

Comment on lines -44 to 48
Copy link
Contributor

Choose a reason for hiding this comment

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

@nicolas-grekas , really thank you, appreciate it a lot!

new Ulid('this is not a ulid');
Expand Down Expand Up @@ -151,7 +153,7 @@ public function testFromBinary()
*/
public function testFromBinaryInvalidFormat(string $ulid)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);

Ulid::fromBinary($ulid);
}
Expand All @@ -178,7 +180,7 @@ public function testFromBase58()
*/
public function testFromBase58InvalidFormat(string $ulid)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);

Ulid::fromBase58($ulid);
}
Expand All @@ -205,7 +207,7 @@ public function testFromBase32()
*/
public function testFromBase32InvalidFormat(string $ulid)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);

Ulid::fromBase32($ulid);
}
Expand All @@ -232,7 +234,7 @@ public function testFromRfc4122()
*/
public function testFromRfc4122InvalidFormat(string $ulid)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);

Ulid::fromRfc4122($ulid);
}
Expand Down
15 changes: 8 additions & 7 deletions src/Symfony/Component/Uid/Tests/UuidTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Uid\Tests;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Uid\Exception\InvalidArgumentException;
use Symfony\Component\Uid\MaxUuid;
use Symfony\Component\Uid\NilUuid;
use Symfony\Component\Uid\Tests\Fixtures\CustomUuid;
Expand All @@ -35,7 +36,7 @@ class UuidTest extends TestCase
*/
public function testConstructorWithInvalidUuid(string $uuid)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid UUID: "'.$uuid.'".');

Uuid::fromString($uuid);
Expand All @@ -58,7 +59,7 @@ public function testInvalidVariant(string $uuid)
$uuid = (string) $uuid;
$class = Uuid::class.'V'.$uuid[14];

$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid UUIDv'.$uuid[14].': "'.$uuid.'".');

new $class($uuid);
Expand Down Expand Up @@ -381,7 +382,7 @@ public function testFromBinary()
*/
public function testFromBinaryInvalidFormat(string $ulid)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);

Uuid::fromBinary($ulid);
}
Expand All @@ -408,7 +409,7 @@ public function testFromBase58()
*/
public function testFromBase58InvalidFormat(string $ulid)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);

Uuid::fromBase58($ulid);
}
Expand All @@ -435,7 +436,7 @@ public function testFromBase32()
*/
public function testFromBase32InvalidFormat(string $ulid)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);

Uuid::fromBase32($ulid);
}
Expand All @@ -462,7 +463,7 @@ public function testFromRfc4122()
*/
public function testFromRfc4122InvalidFormat(string $ulid)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);

Uuid::fromRfc4122($ulid);
}
Expand Down Expand Up @@ -509,7 +510,7 @@ public function testV1ToV6()

public function testV1ToV7BeforeUnixEpochThrows()
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot convert UUID to v7: its timestamp is before the Unix epoch.');

(new UuidV1('9aba8000-ff00-11b0-b3db-3b3fc83afdfc'))->toV7(); // Timestamp is 1969-01-01 00:00:00.0000000
Expand Down
Loading
Loading