diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
index fe887ca9c97bd..65004b9e9fa74 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
+++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
@@ -19,6 +19,7 @@ CHANGELOG
* Made `BrowserKitAssertionsTrait` report the original error message in case of a failure
* Added ability for `config:dump-reference` and `debug:config` to dump and debug kernel container extension configuration.
* Deprecated `session.attribute_bag` service and `session.flash_bag` service.
+ * The `uid:generate` command from the Uid Component is now registered.
5.0.0
-----
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index ce65523745bd5..d4cafc773ea3f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -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\Command\UidGenerateCommand;
use Symfony\Component\Validator\ConstraintValidatorInterface;
use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader;
use Symfony\Component\Validator\ObjectInitializerInterface;
@@ -187,6 +188,9 @@ public function load(array $configs, ContainerBuilder $container)
if (!class_exists(BaseYamlLintCommand::class)) {
$container->removeDefinition('console.command.yaml_lint');
}
+ if (!class_exists(UidGenerateCommand::class)) {
+ $container->removeDefinition('console.command.uid_generate');
+ }
}
// Load Cache configuration first as it is used by other components
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml
index 3ef3108b45d49..833b34f1eaadf 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml
@@ -174,6 +174,10 @@
+
+
+
+
diff --git a/src/Symfony/Component/Uid/CHANGELOG.md b/src/Symfony/Component/Uid/CHANGELOG.md
index 70a35a92916ff..3ff8db2f91969 100644
--- a/src/Symfony/Component/Uid/CHANGELOG.md
+++ b/src/Symfony/Component/Uid/CHANGELOG.md
@@ -7,3 +7,4 @@ CHANGELOG
* added support for UUID
* added support for ULID
* added the component
+ * added `uid:generate` command to generate UUIDs and ULIDs
diff --git a/src/Symfony/Component/Uid/Command/UidGenerateCommand.php b/src/Symfony/Component/Uid/Command/UidGenerateCommand.php
new file mode 100644
index 0000000000000..4986e51dc65dc
--- /dev/null
+++ b/src/Symfony/Component/Uid/Command/UidGenerateCommand.php
@@ -0,0 +1,120 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Uid\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Exception\InvalidArgumentException;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Uid\Ulid;
+use Symfony\Component\Uid\Uuid;
+
+class UidGenerateCommand extends Command
+{
+ protected static $defaultName = 'uid:generate';
+
+ private const UUID_1 = 'uuid-1';
+ private const UUID_3 = 'uuid-3';
+ private const UUID_4 = 'uuid-4';
+ private const UUID_5 = 'uuid-5';
+ private const UUID_6 = 'uuid-6';
+ private const ULID = 'ulid';
+
+ private const TYPES = [
+ self::UUID_1,
+ self::UUID_3,
+ self::UUID_4,
+ self::UUID_5,
+ self::UUID_6,
+ self::ULID,
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function configure()
+ {
+ $typesAsString = implode(', ', self::TYPES);
+
+ $this
+ ->setDefinition([
+ new InputArgument('type', InputArgument::REQUIRED, 'The type/version of the generated UID.'),
+ new InputArgument('namespace', InputArgument::OPTIONAL, 'Namespace for UUID V3 and V5 versions.', ''),
+ new InputArgument('name', InputArgument::OPTIONAL, 'Name for UUID V3 and V5 versions.', ''),
+ new InputOption('base32', null, InputOption::VALUE_NONE, 'Use this option to represent the generated UUID/ULID in base 32.'),
+ new InputOption('base58', null, InputOption::VALUE_NONE, 'Use this option to represent the generated UUID/ULID in base 58.'),
+ ])
+ ->setDescription('Generates a UID, that can be either a ULID or a UUID in a given version.')
+ ->setHelp(<<%command.name% generates UID. This can be a ULID or a UUID
+in a given version. Available types are $typesAsString.
+Examples:
+
+ php %command.full_name% ulid for generating a ULID.
+ php %command.full_name% uuid-1 for generating a UUID in version 1.
+ php %command.full_name% uuid-3 9b7541de-6f87-11ea-ab3c-9da9a81562fc foo for generating a UUID in version 3.
+ php %command.full_name% uuid-4 --base32 for generating a UUID in version 4 represented in base 32.
+
+EOF
+ )
+ ;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $type = $input->getArgument('type');
+ $namespace = $input->getArgument('namespace');
+ $name = $input->getArgument('name');
+
+ if (\in_array($type, [self::UUID_3, self::UUID_5], true) && !Uuid::isValid($namespace)) {
+ throw new InvalidArgumentException('You must specify a valid namespace as a second argument.');
+ }
+
+ switch ($type) {
+ case self::UUID_1:
+ $uid = Uuid::v1();
+ break;
+ case self::UUID_3:
+ $uid = Uuid::v3(Uuid::fromString($namespace), $name);
+ break;
+ case self::UUID_4:
+ $uid = Uuid::v4();
+ break;
+ case self::UUID_5:
+ $uid = Uuid::v5(Uuid::fromString($namespace), $name);
+ break;
+ case self::UUID_6:
+ $uid = Uuid::v6();
+ break;
+ case self::ULID:
+ $uid = new Ulid();
+ break;
+ default:
+ throw new InvalidArgumentException('Invalid UID type. Available values are '.implode(', ', self::TYPES).'.');
+ }
+
+ if ($input->getOption('base32')) {
+ $uid = $uid->toBase32();
+ } elseif ($input->getOption('base58')) {
+ $uid = $uid->toBase58();
+ }
+
+ $output->writeln($uid);
+
+ return 0;
+ }
+}
diff --git a/src/Symfony/Component/Uid/Tests/Command/UidGenerateCommandTest.php b/src/Symfony/Component/Uid/Tests/Command/UidGenerateCommandTest.php
new file mode 100644
index 0000000000000..47415e8079aaf
--- /dev/null
+++ b/src/Symfony/Component/Uid/Tests/Command/UidGenerateCommandTest.php
@@ -0,0 +1,49 @@
+getTester();
+
+ $tester->execute(['type' => 'uuid-1']);
+ $this->assertRegExp('/[a-f\d]{8}\-[a-f\d]{4}\-1[a-f\d]{3}\-[a-f\d]{4}\-[a-f\d]{8}/i', $tester->getDisplay());
+
+ $tester->execute(['type' => 'uuid-3', 'namespace' => 'a1dc606e-741b-11ea-aa36-99e245e7882b', 'name' => 'foo']);
+ $this->assertStringContainsString('ad4ab486-b67f-3d46-881f-21f03d27a68b', $tester->getDisplay());
+
+ $tester->execute(['type' => 'uuid-4']);
+ $this->assertRegExp('/[a-f\d]{8}\-[a-f\d]{4}\-4[a-f\d]{3}\-[a-f\d]{4}\-[a-f\d]{8}/i', $tester->getDisplay());
+
+ $tester->execute(['type' => 'uuid-5', 'namespace' => 'a1dc606e-741b-11ea-aa36-99e245e7882b', 'name' => 'foo']);
+ $this->assertStringContainsString('d87f160a-3cc6-520e-845f-112865bed05c', $tester->getDisplay());
+
+ $tester->execute(['type' => 'uuid-6']);
+ $this->assertRegExp('/[a-f\d]{8}\-[a-f\d]{4}\-6[a-f\d]{3}\-[a-f\d]{4}\-[a-f\d]{8}/i', $tester->getDisplay());
+
+ $tester->execute(['type' => 'ulid']);
+ $this->assertRegExp('/[0-9A-HJKMNP-TV-Z]{26}/i', $tester->getDisplay());
+
+ $tester->execute(['type' => 'uuid-1', '--base32' => true]);
+ $this->assertRegExp('/[0-9A-HJKMNP-TV-Z]{26}/i', $tester->getDisplay());
+
+ $tester->execute(['type' => 'uuid-1', '--base58' => true]);
+ $this->assertRegExp('/[1-9A-HJ-NP-Za-km-z]{22}/i', $tester->getDisplay());
+ }
+
+ public function getTester(): CommandTester
+ {
+ $application = new BaseApplication();
+ $application->add(new UidGenerateCommand());
+ $command = $application->find('uid:generate');
+
+ return new CommandTester($command);
+ }
+}