8000 [Uid] Add UuidFactory to create Ulid and Uuid from timestamps, namesp… · symfony/symfony@88a99dd · GitHub
[go: up one dir, main page]

Skip to content

Commit 88a99dd

Browse files
fancywebnicolas-grekas
authored andcommitted
[Uid] Add UuidFactory to create Ulid and Uuid from timestamps, namespaces and nodes
1 parent 37e1823 commit 88a99dd

File tree

Expand file tree

23 files changed

+833
-27
lines changed

23 files changed

+833
-27
lines changed

src/Symfony/Bridge/Doctrine/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Deprecate `DoctrineTestHelper` and `TestRepositoryFactory`
88
* [BC BREAK] Remove `UuidV*Generator` classes
9+
* Add `UuidGenerator`
910

1011
5.2.0
1112
-----

src/Symfony/Bridge/Doctrine/IdGenerator/UlidGenerator.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,24 @@
1313

1414
use Doctrine\ORM\EntityManager;
1515
use Doctrine\ORM\Id\AbstractIdGenerator;
16+
use Symfony\Component\Uid\Factory\UlidFactory;
1617
use Symfony\Component\Uid\Ulid;
1718

1819
final class UlidGenerator extends AbstractIdGenerator
1920
{
21+
private $factory;
22+
23+
public function __construct(UlidFactory $factory = null)
24+
{
25+
$this->factory = $factory;
26+
}
27+
2028
public function generate(EntityManager $em, $entity): Ulid
2129
{
30+
if ($this->factory) {
31+
return $this->factory->create();
32+
}
33+
2234
return new Ulid();
2335
}
2436
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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\Bridge\Doctrine\IdGenerator;
13+
14+
use Doctrine\ORM\EntityManager;
15+
use Doctrine\ORM\Id\AbstractIdGenerator;
16+
use Symfony\Component\Uid\Factory\UuidFactory;
17+
use Symfony\Component\Uid\Uuid;
18+
19+
final class UuidGenerator extends AbstractIdGenerator
20+
{
21+
private $protoFactory;
22+
private $factory;
23+
private $entityGetter;
24+
25+
public function __construct(UuidFactory $factory = null)
26+
{
27+
$this->protoFactory = $this->factory = $factory ?? new UuidFactory();
28+
}
29+
30+
public function generate(EntityManager $em, $entity): Uuid
31+
{
32+
if (null !== $this->entityGetter) {
33+
if (\is_callable([$entity, $this->entityGetter])) {
34+
return $this->factory->create($entity->{$this->entityGetter}());
35+
}
36+
37+
return $this->factory->create($entity->{$this->entityGetter});
38+
}
39+
40+
return $this->factory->create();
41+
}
42+
43+
/**
44+
* @param Uuid|string|null $namespace
45+
*
46+
* @return static
47+
*/
48+
public function nameBased(string $entityGetter, $namespace = null): self
49+
{
50+
$clone = clone $this;
51+
$clone->factory = $clone->protoFactory->nameBased($namespace);
52+
$clone->entityGetter = $entityGetter;
53+
54+
return $clone;
55+
}
56+
57+
/**
58+
* @return static
59+
*/
60+
public function randomBased(): self
61+
{
62+
$clone = clone $this;
63+
$clone->factory = $clone->protoFactory->randomBased();
64+
$clone->entityGetter = null;
65+
66+
return $clone;
67+
}
68+
69+
/**
70+
* @param Uuid|string|null $node
71+
*
72+
* @return static
73+
*/
74+
public function timeBased($node = null): self
75+
{
76+
$clone = clone $this;
77+
$clone->factory = $clone->protoFactory->timeBased($node);
78+
$clone->entityGetter = null;
79+
80+
return $clone;
81+
}
82+
}

src/Symfony/Bridge/Doctrine/Tests/IdGenerator/UlidGeneratorTest.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use Doctrine\ORM\Mapping\Entity;
1515
use PHPUnit\Framework\TestCase;
1616
use Symfony\Bridge\Doctrine\IdGenerator\UlidGenerator;
17-
use Symfony\Component\Uid\AbstractUid;
17+
use Symfony\Component\Uid\Factory\UlidFactory;
1818
use Symfony\Component\Uid\Ulid;
1919

2020
class UlidGeneratorTest extends TestCase
@@ -25,8 +25,23 @@ public function testUlidCanBeGenerated()
2525
$generator = new UlidGenerator();
2626
$ulid = $generator->generate($em, new Entity());
2727

28-
$this->assertInstanceOf(AbstractUid::class, $ulid);
2928
$this->assertInstanceOf(Ulid::class, $ulid);
3029
$this->assertTrue(Ulid::isValid($ulid));
3130
}
31+
32+
/**
33+
* @requires function \Symfony\Component\Uid\Factory\UlidFactory::create
34+
*/
35+
public function testUlidFactory()
36+
{
37+
$ulid = new Ulid('00000000000000000000000000');
38+
$em = new EntityManager();
39+
$factory = $this->createMock(UlidFactory::class);
40+
$factory->expects($this->any())
41+
->method('create')
42+
->willReturn($ulid);
43+
$generator = new UlidGenerator($factory);
44+
45+
$this->assertSame($ulid, $generator->generate($em, new Entity()));
46+
}
3247
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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\Bridge\Doctrine\Tests\IdGenerator;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
16+
use Symfony\Component\Uid\Factory\UuidFactory;
17+
use Symfony\Component\Uid\NilUuid;
18+
use Symfony\Component\Uid\Uuid;
19+
use Symfony\Component\Uid\UuidV4;
20+
use Symfony\Component\Uid\UuidV6;
21+
22+
/**
23+
* @requires function \Symfony\Component\Uid\Factory\UuidFactory::create
24+
*/
25+
class UuidGeneratorTest extends TestCase
26+
{
27+
public function testUuidCanBeGenerated()
28+
{
29+
$em = new EntityManager();
30+
$generator = new UuidGenerator();
31+
$uuid = $generator->generate($em, new Entity());
32+
33+
$this->assertInstanceOf(Uuid::class, $uuid);
34+
}
35+
36+
public function te 10000 stCustomUuidfactory()
37+
{
38+
$uuid = new NilUuid();
39+
$em = new EntityManager();
40+
$factory = $this->createMock(UuidFactory::class);
41+
$factory->expects($this->any())
42+
->method('create')
43+
->willReturn($uuid);
44+
$generator = new UuidGenerator($factory);
45+
46+
$this->assertSame($uuid, $generator->generate($em, new Entity()));
47+
}
48+
49+
public function testUuidfactory()
50+
{
51+
$em = new EntityManager();
52+
$generator = new UuidGenerator();
53+
$this->assertInstanceOf(UuidV6::class, $generator->generate($em, new Entity()));
54+
55+
$generator = $generator->randomBased();
56+
$this->assertInstanceOf(UuidV4::class, $generator->generate($em, new Entity()));
57+
58+
$generator = $generator->timeBased();
59+
$this->assertInstanceOf(UuidV6::class, $generator->generate($em, new Entity()));
60+
61+
$generator = $generator->nameBased('prop1', Uuid::NAMESPACE_OID);
62+
$this->assertEquals(Uuid::v5(new Uuid(Uuid::NAMESPACE_OID), '3'), $generator->generate($em, new Entity()));
63+
64+
$generator = $generator->nameBased('prop2', Uuid::NAMESPACE_OID);
65+
$this->assertEquals(Uuid::v5(new Uuid(Uuid::NAMESPACE_OID), '2'), $generator->generate($em, new Entity()));
66+
67+
$generator = $generator->nameBased('getProp4', Uuid::NAMESPACE_OID);
68+
$this->assertEquals(Uuid::v5(new Uuid(Uuid::NAMESPACE_OID), '4'), $generator->generate($em, new Entity()));
69+
70+
$factory = new UuidFactory(6, 6, 5, 5, null, Uuid::NAMESPACE_OID);
71+
$generator = new UuidGenerator($factory);
72+
$generator = $generator->nameBased('prop1');
73+
$this->assertEquals(Uuid::v5(new Uuid(Uuid::NAMESPACE_OID), '3'), $generator->generate($em, new Entity()));
74+
}
75+
}
76+
77+
class Entity
78+
{
79+
public $prop1 = 1;
80+
public $prop2 = 2;
81+
82+
public function prop1()
83+
{
84+
return 3;
85+
}
86+
87+
public function getProp4()
88+
{
89+
return 4;
90+
}
91+
}

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CHANGELOG
1010
* Added the `dispatcher` option to `debug:event-dispatcher`
1111
* Added the `event_dispatcher.dispatcher` tag
1212
* Added `assertResponseFormatSame()` in `BrowserKitAssertionsTrait`
13+
* Add support for configuring UUID factory services
1314

1415
5.2.0
1516
-----

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use Symfony\Component\RateLimiter\Policy\TokenBucketLimiter;
3535
use Symfony\Component\Serializer\Serializer;
3636
use Symfony\Component\Translation\Translator;
37+
use Symfony\Component\Uid\Factory\UuidFactory;
3738
use Symfony\Component\Validator\Validation;
3839
use Symfony\Component\WebLink\HttpHeaderSerializer;
3940
use Symfony\Component\Workflow\WorkflowEvents;
@@ -136,6 +137,7 @@ public function getConfigTreeBuilder()
136137
$this->addSecretsSection($rootNode);
137138
$this->addNotifierSection($rootNode);
138139
$this->addRateLimiterSection($rootNode);
140+
$this->addUidSection($rootNode);
139141

140142
return $treeBuilder;
141143
}
@@ -1891,4 +1893,37 @@ private function addRateLimiterSection(ArrayNodeDefinition $rootNode)
18911893
->end()
18921894
;
18931895
}
1896+
1897+
private function addUidSection(ArrayNodeDefinition $rootNode)
1898+
{
1899+
$rootNode
1900+
->children()
1901+
->arrayNode('uid')
1902+
->info('Uid configuration')
1903+
->{class_exists(UuidFactory::class) ? 'canBeDisabled' : 'canBeEnabled'}()
1904+
->addDefaultsIfNotSet()
1905+
->children()
1906+
->enumNode('default_uuid_version')
1907+
->defaultValue(6)
1908+
->values([6, 4, 1])
1909+
->end()
1910+
->enumNode('name_based_uuid_version')
1911+
->defaultValue(5)
1912+
->values([5, 3])
1913+
->end()
1914+
->scalarNode('name_based_uuid_namespace')
1915+
->cannotBeEmpty()
1916+
->end()
1917+
->enumNode('time_based_uuid_version')
1918+
->defaultValue(6)
1919+
->values([6, 1])
1920+
->end()
1921+
->scalarNode('time_based_uuid_node')
1922+
->cannotBeEmpty()
1923+
->end()
1924+
->end()
1925+
->end()
1926+
->end()
1927+
;
1928+
}
18941929
}

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@
160160
use Symfony\Component\Translation\Command\XliffLintCommand as BaseXliffLintCommand;
161161
use Symfony\Component\Translation\PseudoLocalizationTranslator;
162162
use Symfony\Component\Translation\Translator;
163+
use Symfony\Component\Uid\Factory\UuidFactory;
164+
use Symfony\Component\Uid\UuidV4;
163165
use Symfony\Component\Validator\ConstraintValidatorInterface;
164166
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
165167
use Symfony\Component\Validator\ObjectInitializerInterface;
@@ -449,6 +451,14 @@ public function load(array $configs, ContainerBuilder $container)
449451
$loader->load('web_link.php');
450452
}
451453

454+
if ($this->isConfigEnabled($container, $config['uid'])) {
455+
if (!class_exists(UuidFactory::class)) {
456+
throw new LogicException('Uid support cannot be enabled as the Uid component is not installed. Try running "composer require symfony/uid".');
457+
}
458+
459+
$this->registerUidConfiguration($config['uid'], $container, $loader);
460+
}
461+
452462
$this->addAnnotatedClassesToCompile([
453463
'**\\Controller\\',
454464
'**\\Entity\\',
@@ -2322,6 +2332,27 @@ public static function registerRateLimiter(ContainerBuilder $container, string $
23222332
$container->registerAliasForArgument($limiterId, RateLimiterFactory::class, $name.'.limiter');
23232333
}
23242334

2335+
private function registerUidConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader)
2336+
{
2337+
$loader->load('uid.php');
2338+
2339+
$container->getDefinition('uuid.factory')
2340+
->setArguments([
2341+
$config['default_uuid_version'],
2342+
$config['time_based_uuid_version'],
2343+
$config['name_based_uuid_version'],
2344+
UuidV4::class,
2345+
$config['time_based_uuid_node'] ?? null,
2346+
$config['name_based_uuid_namespace'] ?? null,
2347+
])
2348+
;
2349+
2350+
if (isset($config['name_based_uuid_namespace'])) {
2351+
$container->getDefinition('name_based_uuid.factory')
2352+
->setArguments([$config['name_based_uuid_namespace']]);
2353+
}
2354+
}
2355+
23252356
private function resolveTrustedHeaders(array $headers): int
23262357
{
23272358
$trustedHeaders = 0;

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

Lines changed: 32 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,35 @@
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:attribute name="enabled" type="xsd:boolean" />
699+
<xsd:attribute name="default_uuid_version" type="default_uuid_version" />
700+
<xsd:attribute name="name_based_uuid_version" type="name_based_uuid_version" />
701+
<xsd:attribute name="time_based_uuid_version" type="time_based_uuid_version" />
702+
<xsd:attribute name="name_based_uuid_namespace" type="xsd:string" />
703+
<xsd:attribute name="time_based_uuid_node" type="xsd:string" />
704+
</xsd:complexType>
705+
706+
<xsd:simpleType name="default_uuid_version">
707+
<xsd:restriction base="xsd:int">
708+
<xsd:enumeration value="6" />
709+
<xsd:enumeration value="4" />
710+
<xsd:enumeration value="1" />
711+
</xsd:restriction>
712+
</xsd:simpleType>
713+
714+
<xsd:simpleType name="name_based_uuid_version">
715+
<xsd:restriction base="xsd:int">
716+
<xsd:enumeration value="5" />
717+
<xsd:enumeration value="3" />
718+
</xsd:restriction>
719+
</xsd:simpleType>
720+
721+
<xsd:simpleType name="time_based_uuid_version">
722+
<xsd:restriction base="xsd:int">
723+
<xsd:enumeration value="6" />
724+
<xsd:enumeration value="1" />
725+
</xsd:restriction>
726+
</xsd:simpleType>
695727
</xsd:schema>

0 commit comments

Comments
 (0)
0