Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 311c10b

Browse filesBrowse files
committed
[Uid] Add UidFactory to create Ulid and Uuid from timestamps and randomness/nodes
1 parent 72a82c3 commit 311c10b
Copy full SHA for 311c10b

File tree

13 files changed

+518
-22
lines changed
Filter options

13 files changed

+518
-22
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+69Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter;
3535
use Symfony\Component\Serializer\Serializer;
3636
use Symfony\Component\Translation\Translator;
37+
use Symfony\Component\Uid\AbstractUid;
38+
use Symfony\Component\Uid\UuidV1;
39+
use Symfony\Component\Uid\UuidV3;
40+
use Symfony\Component\Uid\UuidV5;
41+
use Symfony\Component\Uid\UuidV6;
3742
use Symfony\Component\Validator\Validation;
3843
use Symfony\Component\WebLink\HttpHeaderSerializer;
3944
use Symfony\Component\Workflow\WorkflowEvents;
@@ -136,6 +141,7 @@ public function getConfigTreeBuilder()
136141
$this->addSecretsSection($rootNode);
137142
$this->addNotifierSection($rootNode);
138143
$this->addRateLimiterSection($rootNode);
144+
$this->addUidSection($rootNode);
139145

140146
return $treeBuilder;
141147
}
@@ -1891,4 +1897,67 @@ private function addRateLimiterSection(ArrayNodeDefinition $rootNode)
18911897
->end()
18921898
;
18931899
}
1900+
1901+
private function addUidSection(ArrayNodeDefinition $rootNode)
1902+
{
1903+
$rootNode
1904+
->children()
1905+
->arrayNode('uid')
1906+
->info('Uid configuration')
1907+
->{class_exists(AbstractUid::class) ? 'canBeDisabled' : 'canBeEnabled'}()
1908+
->children()
1909+
->arrayNode('uuid_factory')
1910+
->addDefaultsIfNotSet()
1911+
->children()
1912+
->enumNode('default_named_version')
1913+
->defaultValue(UuidV5::class)
1914+
->cannotBeEmpty()
1915+
->values([UuidV5::class, UuidV3::class])
1916+
->beforeNormalization()
1917+
->always()
1918+
->then(static function ($value) {
1919+
if ('v5' === $value) {
1920+
return UuidV5::class;
1921+
}
1922+
1923+
if ('v3' === $value) {
1924+
return UuidV3::class;
1925+
}
1926+
1927+
return $value;
1928+
})
1929+
->end()
1930+
->end()
1931+
->enumNode('default_timed_version')
1932+
->defaultValue(UuidV6::class)
1933+
->cannotBeEmpty()
1934+
->values([UuidV6::class, UuidV1::class])
1935+
->beforeNormalization()
1936+
->always()
1937+
->then(static function ($value) {
1938+
if ('v6' === $value) {
1939+
return UuidV6::class;
1940+
}
1941+
1942+
if ('v1' === $value) {
1943+
return UuidV1::class;
1944+
}
1945+
1946+
return $value;
1947+
})
1948+
->end()
1949+
->end()
1950+
->scalarNode('default_namespace')
1951+
->cannotBeEmpty()
1952+
->end()
1953+
->scalarNode('default_node')
1954+
->cannotBeEmpty()
1955+
->end()
1956+
->end()
1957+
->end()
1958+
->end()
1959+
->end()
1960+
->end()
1961+
;
1962+
}
18941963
}

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+28Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
use Symfony\Component\Translation\Command\XliffLintCommand as BaseXliffLintCommand;
159159
use Symfony\Component\Translation\PseudoLocalizationTranslator;
160160
use Symfony\Component\Translation\Translator;
161+
use Symfony\Component\Uid\AbstractUid;
161162
use Symfony\Component\Validator\ConstraintValidatorInterface;
162163
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
163164
use Symfony\Component\Validator\ObjectInitializerInterface;
@@ -447,6 +448,14 @@ public function load(array $configs, ContainerBuilder $container)
447448
$loader->load('web_link.php');
448449
}
449450

451+
if ($this->isConfigEnabled($container, $config['uid'])) {
452+
if (!class_exists(AbstractUid::class)) {
453+
throw new LogicException('Uid support cannot be enabled as the Uid component is not installed. Try running "composer require symfony/uid".');
454+
}
455+
456+
$this->registerUidConfiguration($config['uid'], $container, $loader);
457+
}
458+
450459
$this->addAnnotatedClassesToCompile([
451460
'**\\Controller\\',
452461
'**\\Entity\\',
@@ -2312,6 +2321,25 @@ public static function registerRateLimiter(ContainerBuilder $container, string $
23122321
$container->registerAliasForArgument($limiterId, RateLimiterFactory::class, $name.'.limiter');
23132322
}
23142323

2324+
private function registerUidConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader)
2325+
{
2326+
$loader->load('uid.php');
2327+
2328+
$uidFactory = $container->getDefinition('uuid.factory');
2329+
$uidFactory->setArguments([
2330+
$config['uuid_factory']['default_named_version'],
2331+
$config['uuid_factory']['default_timed_version'],
2332+
]);
2333+
2334+
if (isset($config['uuid_factory']['default_namespace'])) {
2335+
$uidFactory->addMethodCall('withDefaultNamespace', [$config['uuid_factory']['default_namespace']], true);
2336+
}
2337+
2338+
if (isset($config['uuid_factory']['default_node'])) {
2339+
$uidFactory->addMethodCall('withDefaultNode', [$config['uuid_factory']['default_node']], true);
2340+
}
2341+
}
2342+
23152343
private function resolveTrustedHeaders(array $headers): int
23162344
{
23172345
$trustedHeaders = 0;

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+27Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<xsd:element name="mailer" type="mailer" minOccurs="0" maxOccurs="1" />
3636
<xsd:element name="http-cache" type="http_cache" minOccurs="0" maxOccurs="1" />
3737
<xsd:element name="rate-limiter" type="rate_limiter" minOccurs="0" maxOccurs="1" />
38+
<xsd:element name="uid" type="uid" minOccurs="0" maxOccurs="1" />
3839
</xsd:choice>
3940

4041
<xsd:attribute name="http-method-override" type="xsd:boolean" />
@@ -692,4 +693,30 @@
692693
<xsd:attribute name="interval" type="xsd:string" />
693694
<xsd:attribute name="amount" type="xsd:int" />
694695
</xsd:complexType>
696+
697+
<xsd:complexType name="uid">
698+
<xsd:sequence>
699+
<xsd:element name="uid_factory" type="uid_factory" minOccurs="0" maxOccurs="1" />
700+
</xsd:sequence>
701+
<xsd:attribute name="enabled" type="xsd:boolean" />
702+
</xsd:complexType>
703+
704+
<xsd:complexType name="uid_factory">
705+
<xsd:attribute name="default_named_version" type="uid_named_version" />
706+
<xsd:attribute name="default_timed_version" type="uid_timed_version" />
707+
</xsd:complexType>
708+
709+
<xsd:simpleType name="uid_named_version">
710+
<xsd:restriction base="xsd:string">
711+
<xsd:enumeration value="v5" />
712+
<xsd:enumeration value="v3" />
713+
</xsd:restriction>
714+
</xsd:simpleType>
715+
716+
<xsd:simpleType name="uid_timed_version">
717+
<xsd:restriction base="xsd:string">
718+
<xsd:enumeration value="v6" />
719+
<xsd:enumeration value="v1" />
720+
</xsd:restriction>
721+
</xsd:simpleType>
695722
</xsd:schema>
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
13+
14+
use Symfony\Component\Uid\UlidFactory;
15+
use Symfony\Component\Uid\UuidFactory;
16+
17+
return static function (ContainerConfigurator $container) {
18+
$container->services()
19+
->set('uuid.factory', UuidFactory::class)
20+
->alias(UuidFactory::class, 'uuid.factory')
21+
22+
->set('ulid.factory', UlidFactory::class)
23+
->alias(UlidFactory::class, 'ulid.factory')
24+
;
25+
};

‎src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
use Symfony\Component\Mailer\Mailer;
2323
use Symfony\Component\Messenger\MessageBusInterface;
2424
use Symfony\Component\Notifier\Notifier;
25+
use Symfony\Component\Uid\UuidV5;
26+
use Symfony\Component\Uid\UuidV6;
2527

2628
class ConfigurationTest extends TestCase
2729
{
@@ -563,6 +565,13 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor
563565
'enabled' => false,
564566
'limiters' => [],
565567
],
568+
'uid' => [
569+
'enabled' => true,
570+
'uuid_factory' => [
571+
'default_named_version' => UuidV5::class,
572+
'default_timed_version' => UuidV6::class,
573+
],
574+
],
566575
];
567576
}
568577
}

‎src/Symfony/Component/Uid/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Uid/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Add `AbstractUid::fromBinary()`, `AbstractUid::fromBase58()`, `AbstractUid::fromBase32()` and `AbstractUid::fromRfc4122()`
8+
* Add `UuidFactory` and `UlidFactory`
89

910
5.2.0
1011
-----
+41Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Uid\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Uid\UlidFactory;
16+
17+
final class UlidFactoryTest extends TestCase
18+
{
19+
public function testCreate()
20+
{
21+
$ulidFactory = new UlidFactory();
22+
23+
$ulidFactory->create();
24+
25+
$ulid1 = $ulidFactory->create('999999');
26+
$this->assertSame(999.999, $ulid1->getTime());
27+
$ulid2 = $ulidFactory->create('999999');
28+
$this->assertSame(999.999, $ulid2->getTime());
29+
30+
$this->assertFalse($ulid1->equals($ulid2));
31+
$this->assertSame(-1, ($ulid1->compare($ulid2)));
32+
}
33+
34+
public function testCreateWithInvalidTimestamp()
35+
{
36+
$this->expectException(\InvalidArgumentException::class);
37+
$this->expectExceptionMessage('The timestamp must be a positive number.');
38+
39+
(new UlidFactory())->create('-1000');
40+
}
41+
}
+108Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Uid\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Uid\UuidFactory;
16+
use Symfony\Component\Uid\Uuid;
17+
use Symfony\Component\Uid\UuidV1;
18+
use Symfony\Component\Uid\UuidV3;
19+
use Symfony\Component\Uid\UuidV4;
20+
use Symfony\Component\Uid\UuidV5;
21+
use Symfony\Component\Uid\UuidV6;
22+
23+
final class UuidFactoryTest extends TestCase
24+
{
25+
public function testCreateNamedDefaultVersion()
26+
{
27+
$this->assertInstanceOf(UuidV5::class, (new UuidFactory())->createNamed('foo'));
28+
$this->assertInstanceOf(UuidV3::class, (new UuidFactory(UuidV3::class))->createNamed('foo'));
29+
}
30+
31+
public function testCreateNamed()
32+
{
33+
$uuidFactory = new UuidFactory();
34+
35+
// Test custom namespace
36+
$uuid1 = $uuidFactory->createNamed('foo', Uuid::fromString('6f80c216-0492-4421-bd82-c10ab929ae84'));
37+
$this->assertInstanceOf(UuidV5::class, $uuid1);
38+
$this->assertSame('d521ceb7-3e31-5954-b873-92992c697ab9', (string) $uuid1);
39+
40+
// Test default namespace
41+
$uuidFactory = $uuidFactory->withDefaultNamespace(Uuid::fromString('6f80c216-0492-4421-bd82-c10ab929ae84'));
42+
$uuid2 = $uuidFactory->createNamed('foo');
43+
$this->assertInstanceOf(UuidV5::class, $uuid2);
44+
$this->assertTrue($uuid1->equals($uuid2));
45+
46+
// Test default namespace override
47+
$uuid3 = $uuidFactory->createNamed('foo', Uuid::v4());
48+
$this->assertFalse($uuid2->equals($uuid3));
49+
50+
// Test version override
51+
$uuid4 = $uuidFactory->createNamed('foo', null, UuidV3::class);
52+
$this->assertInstanceOf(UuidV3::class, $uuid4);
53+
}
54+
55+
public function testCreateNamedWithUnsupportedVersion()
56+
{
57+
$this->expectException(\InvalidArgumentException::class);
58+
$this->expectExceptionMessage('The "Symfony\Component\Uid\UuidV1" version is unsupported.');
59+
60+
(new UuidFactory())->createNamed('foo', null, UuidV1::class);
61+
}
62+
63+
public function testCreateTimedDefaultVersion()
64+
{
65+
$this->assertInstanceOf(UuidV6::class, (new UuidFactory())->createTimed());
66+
$this->assertInstanceOf(UuidV1::class, (new UuidFactory(null, UuidV1::class))->createTimed());
67+
}
68+
69+
public function testCreateTimed()
70+
{
71+
$uuidFactory = new UuidFactory();
72+
73+
// Test custom timestamp and node
74+
$uuid1 = $uuidFactory->createTimed('138303697380560000', Uuid::fromString('6f80c216-0492-4421-bd82-c10ab929ae84'));
75+
$this->assertInstanceOf(UuidV6::class, $uuid1);
76+
$this->assertSame(1611076938.056, $uuid1->getTime());
77+
$this->assertSame('c10ab929ae84', $uuid1->getNode());
78+
79+
// Test default node
80+
$uuidFactory = $uuidFactory->withDefaultNode(Uuid::fromString('6f80c216-0492-4421-bd82-c10ab929ae84'));
81+
$uuid2 = $uuidFactory->createTimed();
82+
$this->assertInstanceOf(UuidV6::class, $uuid2);
83+
$this->assertSame('c10ab929ae84', $uuid2->getNode());
84+
85+
// Test default node override
86+
$uuid3 = $uuidFactory->createTimed(null, Uuid::fromString('7c1ede70-3586-48ed-a984-23c8018d9174'));
87+
$this->assertInstanceOf(UuidV6::class, $uuid3);
88+
$this->assertSame('23c8018d9174', $uuid3->getNode());
89+
90+
// Test version override
91+
$uuid4 = $uuidFactory->createTimed(null, null, UuidV1::class);
92+
$this->assertInstanceOf(UuidV1::class, $uuid4);
93+
$this->assertSame($uuid2->getNode(), $uuid4->getNode());
94+
}
95+
96+
public function testCreateTimedWithUnsupportedVersion()
97+
{
98+
$this->expectException(\InvalidArgumentException::class);
99+
$this->expectExceptionMessage('The "Symfony\Component\Uid\UuidV4" version is unsupported.');
100+
101+
(new UuidFactory())->createTimed(null, null, UuidV4::class);
102+
}
103+
104+
public function testCreateRandom()
105+
{
106+
$this->assertInstanceOf(UuidV4::class, (new UuidFactory())->createRandom());
107+
}
108+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.