diff --git a/.idea/php.xml b/.idea/php.xml
index 0eee0f9..04a4d82 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -12,109 +12,109 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/symfony-skeleton.iml b/.idea/symfony-skeleton.iml
index f01cd69..ce06798 100644
--- a/.idea/symfony-skeleton.iml
+++ b/.idea/symfony-skeleton.iml
@@ -5,110 +5,110 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/composer.json b/composer.json
index 5dc7867..ceacc41 100644
--- a/composer.json
+++ b/composer.json
@@ -15,6 +15,7 @@
"spiral/roadrunner-cli": "^2.7",
"symfony/console": "7.3.*",
"symfony/dotenv": "7.3.*",
+ "symfony/filesystem": "7.3.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "7.3.*",
"symfony/runtime": "7.3.*",
diff --git a/composer.lock b/composer.lock
index bdfc392..447966c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "549a8c5317802e826068863f2c7beaf1",
+ "content-hash": "f992818288ab4ae1df2320cfb4535432",
"packages": [
{
"name": "baldinof/roadrunner-bundle",
diff --git a/src/Maker/Bundle/Bundle.tpl.php b/src/Maker/Bundle/Bundle.tpl.php
new file mode 100644
index 0000000..0d64c9d
--- /dev/null
+++ b/src/Maker/Bundle/Bundle.tpl.php
@@ -0,0 +1,12 @@
+= "
+
+declare(strict_types=1);
+
+namespace = $namespace; ?>;
+
+= $use_statements; ?>
+
+final class = $class_name; ?> extends Bundle
+{
+
+}
diff --git a/src/Maker/Bundle/BundleMaker.php b/src/Maker/Bundle/BundleMaker.php
new file mode 100644
index 0000000..c2eead9
--- /dev/null
+++ b/src/Maker/Bundle/BundleMaker.php
@@ -0,0 +1,130 @@
+fs = new Filesystem();
+ $this->srcDir = dirname(__DIR__);
+ }
+
+ public static function getCommandName(): string
+ {
+ return 'make:bundle';
+ }
+
+ public static function getCommandDescription(): string
+ {
+ return 'Create a new bundle';
+ }
+
+ public function configureCommand(Command $command, InputConfiguration $inputConfig): void
+ {
+ $command
+ ->addArgument(
+ name: 'name',
+ mode: InputArgument::OPTIONAL,
+ description: sprintf(
+ 'Choose a bundle name (e.g. %sBundle>)',
+ Str::asClassName(
+ Str::getRandomTerm()
+ )
+ )
+ );
+ }
+
+ public function configureDependencies(DependencyBuilder $dependencies)
+ {
+ // TODO: Implement configureDependencies() method.
+ }
+
+ private function createBundleFile(Generator $generator, string $bundleName): void
+ {
+ $commandClassNameDetails = $generator->createClassNameDetails(
+ name: $bundleName,
+ namespacePrefix: $bundleName,
+ );
+
+ $useStatements = new UseStatementGenerator([
+ Bundle::class,
+ ]);
+
+ $generator->generateClass(
+ className: $commandClassNameDetails->getFullName(),
+ templateName: "$this->srcDir/Bundle/Bundle.tpl.php",
+ variables: [
+ 'class_name' => $bundleName,
+ 'use_statements' => $useStatements,
+ 'bundle_configuration_root' => Str::asSnakeCase($bundleName),
+ ]
+ );
+
+ $generator->writeChanges();
+ }
+
+ private function createConfigurationFile(Generator $generator, string $bundleName): void
+ {
+ $commandClassNameDetails = $generator->createClassNameDetails(
+ name: 'Configuration',
+ namespacePrefix: "$bundleName\DependencyInjection",
+ );
+
+ $useStatements = new UseStatementGenerator([
+ TreeBuilder::class,
+ ConfigurationInterface::class,
+ ]);
+
+ $generator->generateClass(
+ className: $commandClassNameDetails->getFullName(),
+ templateName: "$this->srcDir/Bundle/Configuration.tpl.php",
+ variables: [
+ 'class_name' => $bundleName,
+ 'use_statements' => $useStatements,
+ 'bundle_configuration_root' => Str::asSnakeCase($bundleName),
+ ]
+ );
+
+ $generator->writeChanges();
+ }
+
+ public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void
+ {
+ $bundleName = ucfirst(
+ trim($input->getArgument('name'))
+ );
+
+ if (!str_ends_with($bundleName, 'Bundle')) {
+ $bundleName = "{$bundleName}Bundle";
+ }
+
+ if ($this->fs->exists("$this->srcDir/$bundleName")) {
+ throw new \Exception('Bundle already exists');
+ }
+
+ $this->createBundleFile($generator, $bundleName);
+ $this->createConfigurationFile($generator, $bundleName);
+ $this->writeSuccessMessage($io);
+ }
+}
diff --git a/src/Maker/Bundle/Configuration.tpl.php b/src/Maker/Bundle/Configuration.tpl.php
new file mode 100644
index 0000000..f703349
--- /dev/null
+++ b/src/Maker/Bundle/Configuration.tpl.php
@@ -0,0 +1,20 @@
+= "
+
+declare(strict_types=1);
+
+namespace = $namespace; ?>;
+
+= $use_statements; ?>
+
+final class = $class_name; ?> implements ConfigurationInterface
+{
+ public function getConfigTreeBuilder(): TreeBuilder
+ {
+ $treeBuilder = new TreeBuilder('= $bundle_configuration_root; ?>');
+
+ $treeBuilder->getRootNode()
+ ->end();
+
+ return $treeBuilder;
+ }
+}