8000 [Uid] add autowirable UidFactory by nicolas-grekas · Pull Request #36097 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Uid] add autowirable UidFactory #36097

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
use Symfony\Component\String\Slugger\SluggerInterface;
use Symfony\Component\Translation\Command\XliffLintCommand as BaseXliffLintCommand;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Uid\UidFactory;
use Symfony\Component\Validator\ConstraintValidatorInterface;
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
use Symfony\Component\Validator\ObjectInitializerInterface;
Expand Down Expand Up @@ -176,6 +177,11 @@ public function load(array $configs, ContainerBuilder $container)
$container->setAlias(PsrEventDispatcherInterface::class, 'event_dispatcher');
}

if (!class_exists(UidFactory::class)) {
$container->getDefinition('uid.factory')
->addError('You cannot use the "uid.factory" service since the Uid component is not installed. Try running "composer require symfony/uid".');
}

$container->registerAliasForArgument('parameter_bag', PsrContainerInterface::class);

if (class_exists(Application::class)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,8 @@
<factory class="Symfony\Component\String\LazyString" method="fromCallable" />
<argument type="service" id="container.getenv" />
</service>

<service id="uid.factory" class="Symfony\Component\Uid\UidFactory" />
<service id="Symfony\Component\Uid\UidFactory" alias="uid.factory" />
</services>
</container>
120 changes: 120 additions & 0 deletions src/Symfony/Component/Uid/Tests/UidFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

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

namespace Symfony\Tests\Component\Uid;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Uid\UidFactory;
use Symfony\Component\Uid\Ulid;
use Symfony\Component\Uid\UuidV1;
use Symfony\Component\Uid\UuidV3;
use Symfony\Component\Uid\UuidV4;
use Symfony\Component\Uid\UuidV5;
use Symfony\Component\Uid\UuidV6;

class UidFactoryTest extends TestCase
{
public function testDefaults()
{
$factory = new UidFactory();

$this->assertInstanceOf(Ulid::class, $factory->ulid());
$this->assertInstanceOf(UuidV1::class, $factory->uuidV1());
$this->assertInstanceOf(UuidV3::class, $factory->uuidV3($factory->uuidV1(), 'foo'));
$this->assertInstanceOf(UuidV4::class, $factory->uuidV4());
$this->assertInstanceOf(UuidV5::class, $factory->uuidV5($factory->uuidV1(), 'foo'));
$this->assertInstanceOf(UuidV6::class, $factory->uuidV6());
}

public function testV1()
{
$v1 = 'caa9884e-105e-11b6-8101-010101010101';
$entropySource = function (int $bytes) use (&$called) {
$this->assertSame(8, $bytes);

return "\1\1\1\1\1\1\1\1";
};
$factory = new UidFactory($entropySource);
$uuid = (string) $factory->uuidV1();
$this->assertSame('-8101-010101010101', substr($uuid, -18));
$this->assertNotSame($v1, $uuid);

$timeSource = function () {
return '1111111112345678';
};
$factory = new UidFactory(null, $timeSource);
$uuid = (string) $factory->uuidV1();
$this->assertSame('caa9884e-105e-11b6', substr($uuid, 0, 18));
$this->assertNotSame($v1, $uuid);

$factory = new UidFactory($entropySource, $timeSource);
$this->assertSame($v1, (string) $factory->uuidV1());
}

public function testV6()
{
$v6 = '1b6105ec-aa98-684e-8102-030405060708';
$entropySource = function (int $bytes) use (&$called) {
$this->assertSame(8, $bytes);

return "\1\2\3\4\5\6\7\x08";
};
$factory = new UidFactory($entropySource);
$uuid = (string) $factory->uuidV6();
$this->assertSame('-8102-030405060708', substr($uuid, -18));
$this->assertNotSame($v6, $uuid);

$timeSource = function () {
return '1111111112345678';
};
$factory = new UidFactory(null, $timeSource);
$uuid = (string) $factory->uuidV6();
$this->assertSame('1b6105ec-aa98-684e', substr($uuid, 0, 18));
$this->assertNotSame($v6, $uuid);

$factory = new UidFactory($entropySource, $timeSource);
$this->assertSame($v6, (string) $factory->uuidV6());
}

public function testUlid()
{
$randomSource = function (int $bytes) use (&$called) {
$this->assertSame(10, $bytes);

return "\0\1\2\3\4\5\6\7\x08\0";
};
$timeSource = function () {
return '1111111111112345678';
};
$factory = new UidFactory(null, $timeSource, $randomSource);

$this->assertSame('351R94XWJ20001G0G3010501G7', (string) $factory->ulid());
$this->assertSame('351R94XWJ20001G0G3010501G8', (string) $factory->ulid());

$timeSource = function () {
return '1011111111112345678';
};
$factory = new UidFactory(null, $timeSource, $randomSource);
$this->assertSame('2VYQ1XRMJ20001G0G3010501G9', (string) $factory->ulid());
}

public function testV4()
{
$randomSource = function (int $bytes) use (&$called) {
$this->assertSame(16, $bytes);

return "\0\1\2\3\4\5\6\7\x08\x70\x60\x50\x40\x30\x20\x10";
};
$factory = new UidFactory(null, null, $randomSource);

$this->assertSame('00010203-0405-4607-8870-605040302010', (string) $factory->uuidV4());
}
}
20 changes: 10 additions & 10 deletions src/Symfony/Component/Uid/Tests/UlidTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
namespace Symfony\Tests\Component\Uid;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Uid\UidFactory;
use Symfony\Component\Uid\Ulid;
use Symfony\Component\Uid\UuidV4;

class UlidTest extends TestCase
{
Expand All @@ -22,8 +22,8 @@ class UlidTest extends TestCase
*/
public function testGenerate()
{
$a = new Ulid();
$b = new Ulid();
$a = (new UidFactory())->ulid();
$b = (new UidFactory())->ulid();

$this->assertSame(0, strncmp($a, $b, 20));
$a = base_convert(strtr(substr($a, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10);
Expand Down Expand Up @@ -52,7 +52,7 @@ public function testBinary()

public function testFromUuid()
{
$uuid = new UuidV4();
$uuid = (new UidFactory())->uuidV4();

$ulid = Ulid::fromString($uuid);

Expand All @@ -78,7 +78,7 @@ public function testBase58()
public function testGetTime()
{
$time = microtime(false);
$ulid = new Ulid();
$ulid = (new UidFactory())->ulid();
$time = substr($time, 11).substr($time, 1, 4);

$this->assertSame((float) $time, $ulid->getTime());
Expand All @@ -92,8 +92,8 @@ public function testIsValid()

public function testEquals()
{
$a = new Ulid();
$b = new Ulid();
$a = (new UidFactory())->ulid();
$b = (new UidFactory())->ulid();

$this->assertTrue($a->equals($a));
$this->assertFalse($a->equals($b));
Expand All @@ -105,15 +105,15 @@ public function testEquals()
*/
public function testCompare()
{
$a = new Ulid();
$b = new Ulid();
$a = (new UidFactory())->ulid();
$b = (new UidFactory())->ulid();

$this->assertSame(0, $a->compare($a));
$this->assertLessThan(0, $a->compare($b));
$this->assertGreaterThan(0, $b->compare($a));

usleep(1001);
$c = new Ulid();
$c = (new UidFactory())->ulid();

$this->assertLessThan(0, $b->compare($c));
$this->assertGreaterThan(0, $c->compare($b));
Expand Down
14 changes: 7 additions & 7 deletions src/Symfony/Component/Uid/Tests/UuidTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

use PHPUnit\Framework\TestCase;
use Symfony\Component\Uid\NilUuid;
use Symfony\Component\Uid\Ulid;
use Symfony\Component\Uid\UidFactory;
use Symfony\Component\Uid\Uuid;
use Symfony\Component\Uid\UuidV1;
use Symfony\Component\Uid\UuidV3;
Expand Down Expand Up @@ -44,7 +44,7 @@ public function testConstructorWithValidUuid()

public function testV1()
{
$uuid = Uuid::v1();
$uuid = (new UidFactory())->uuidV1();

$this->assertInstanceOf(UuidV1::class, $uuid);

Expand All @@ -56,28 +56,28 @@ public function testV1()

public function testV3()
{
$uuid = Uuid::v3(new UuidV4(self::A_UUID_V4), 'the name');
$uuid = (new UidFactory())->uuidV3(Uuid::fromString(self::A_UUID_V4), 'the name');

$this->assertInstanceOf(UuidV3::class, $uuid);
}

public function testV4()
{
$uuid = Uuid::v4();
$uuid = (new UidFactory())->uuidV4();

$this->assertInstanceOf(UuidV4::class, $uuid);
}

public function testV5()
{
$uuid = Uuid::v5(new UuidV4(self::A_UUID_V4), 'the name');
$uuid = (new UidFactory())->uuidV5(Uuid::fromString(self::A_UUID_V4), 'the name');

$this->assertInstanceOf(UuidV5::class, $uuid);
}

public function testV6()
{
$uuid = Uuid::v6();
$uuid = (new UidFactory())->uuidV6();

$this->assertInstanceOf(UuidV6::class, $uuid);

Expand All @@ -98,7 +98,7 @@ public function testBinary()

public function testFromUlid()
{
$ulid = new Ulid();
$ulid = (new UidFactory())->ulid();
$uuid = Uuid::fromString($ulid);

$this->assertSame((string) $ulid, $uuid->toBase32());
Expand Down
77 changes: 77 additions & 0 deletions src/Symfony/Component/Uid/UidFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

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

namespace Symfony\Component\Uid;

/**
* A factory to create several kind of unique identifiers.
*
* @experimental in 5.1
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class UidFactory
{
private $entropySource;
private $timeSource;
private $randomSource;

public function __construct(callable $entropySource = null, callable $timeSource = null, callable $randomSource = null)
{
$this->entropySource = $entropySource;
$this->timeSource = $timeSource;
$this->randomSource = $randomSource;
}

public function ulid(): Ulid
{
return new Ulid(Ulid::generate($this->timeSource, $this->randomSource));
}

public function uuidV1(): UuidV1
{
return new UuidV1(UuidV1::generate($this->entropySource, $this->timeSource));
}

public function uuidV3(Uuid $namespace, string $name): UuidV3
{
return new UuidV3(uuid_generate_md5($namespace, $name));
}

public function uuidV4(): UuidV4
{
if (!$this->randomSource) {
$uuid = random_bytes(16);
} elseif (!\is_string($uuid = ($this->randomSource)(16)) || 16 !== \strlen($uuid)) {
throw new \LogicException('The random source must return 8 bytes.');
}

$uuid[6] = $uuid[6] & "\x0F" | "\x40";
$uuid[8] = $uuid[8] & "\x3F" | "\x80";
$uuid = bin2hex($uuid);
$uuid = substr($uuid, 0, 8).'-'.substr($uuid, 8, 4).'-'.substr($uuid, 12, 4).'-'.substr($uuid, 16, 4).'-'.substr($uuid, 20, 12);

return new UuidV4($uuid);
}

public function uuidV5(Uuid $namespace, string $name): UuidV5
{
return new UuidV5(uuid_generate_sha1($namespace, $name));
}

public function uuidV6(): UuidV6
{
$uuid = UuidV1::generate($this->entropySource, $this->timeSource);
$uuid = substr($uuid, 15, 3).substr($uuid, 9, 4).$uuid[0].'-'.substr($uuid, 1, 4).'-6'.substr($uuid, 5, 3).substr($uuid, 18);

return new UuidV6($uuid);
}
}
Loading
0