diff --git a/README.md b/README.md
index 81fbaeb..d13cb06 100644
--- a/README.md
+++ b/README.md
@@ -137,6 +137,20 @@ Ejecuta los tests del plugin. Opcionalmente especifica la ruta de FacturaScripts
#### `fsmaker zip`
Genera un archivo ZIP del plugin listo para distribución.
+#### `fsmaker web`
+Inicia una interfaz web local para ejecutar comandos de fsmaker desde el navegador.
+
+```bash
+fsmaker web
+```
+
+Opciones útiles:
+
+```bash
+fsmaker web --port=8788
+fsmaker web --host=0.0.0.0 --no-open
+```
+
## ✅ Requisitos
- PHP 8.1 o superior
@@ -223,6 +237,14 @@ cd MiPlugin/
fsmaker zip
```
+### Usar interfaz web local
+```bash
+cd MiPlugin/
+fsmaker web
+# abre http://127.0.0.1:8787
+# en "Respuestas" escribe una por línea en orden de los prompts
+```
+
### Ejecutar con mayor verbosidad
```bash
fsmaker model -v # Verbose
@@ -233,4 +255,4 @@ fsmaker model -vvv # Debug
## 📞 Issues / Feedback
- 💬 **Contacto**: https://facturascripts.com/contacto
-- 🐛 **GitHub**: https://github.com/facturascripts/fsmaker
\ No newline at end of file
+- 🐛 **GitHub**: https://github.com/facturascripts/fsmaker
diff --git a/composer.json b/composer.json
index f99e5cd..97bfc83 100644
--- a/composer.json
+++ b/composer.json
@@ -24,7 +24,8 @@
"ext-mbstring": "*",
"ext-ctype": "*",
"laravel/prompts": "^0.3.10",
- "symfony/console": "^6.4 || ^7.0"
+ "symfony/console": "^6.4 || ^7.0",
+ "symfony/http-foundation": "^7.4"
},
"bin": ["bin/fsmaker"],
"require-dev": {
diff --git a/src/Command/Web/WebCommand.php b/src/Command/Web/WebCommand.php
new file mode 100644
index 0000000..9d19619
--- /dev/null
+++ b/src/Command/Web/WebCommand.php
@@ -0,0 +1,54 @@
+addOption('host', null, InputOption::VALUE_REQUIRED, 'Host', '127.0.0.1')
+ ->addOption('port', null, InputOption::VALUE_REQUIRED, 'Puerto', '8787')
+ ->addOption('no-open', null, InputOption::VALUE_NONE, 'No abrir navegador');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $host = (string) $input->getOption('host');
+ $port = (int) $input->getOption('port');
+ $router = dirname(__DIR__, 3) . '/src/Web/router.php';
+
+ if (!file_exists($router)) {
+ $output->writeln('Router no encontrado.');
+ return Command::FAILURE;
+ }
+
+ $url = "http://$host:$port";
+ $output->writeln("Servidor iniciado: $url — Ctrl+C para detener.");
+
+ if (!$input->getOption('no-open')) {
+ $this->openBrowser($url);
+ }
+
+ passthru(sprintf('"%s" -S %s:%d "%s"', PHP_BINARY, $host, $port, $router), $code);
+
+ return $code === 0 ? Command::SUCCESS : Command::FAILURE;
+ }
+
+ private function openBrowser(string $url): void
+ {
+ $u = escapeshellarg($url);
+ match (PHP_OS_FAMILY) {
+ 'Windows' => @pclose(@popen("start \"\" $u", 'r')),
+ 'Darwin' => @shell_exec("open $u > /dev/null 2>&1 &"),
+ default => @shell_exec("xdg-open $u > /dev/null 2>&1 &"),
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Console/Application.php b/src/Console/Application.php
index b7e1afc..8269995 100644
--- a/src/Console/Application.php
+++ b/src/Console/Application.php
@@ -172,6 +172,7 @@ private function getCommands(): array
new \fsmaker\Command\Test\TestCommand(),
new \fsmaker\Command\Test\RunTestsCommand(),
new \fsmaker\Command\View\ViewCommand(),
+ new \fsmaker\Command\Web\WebCommand(),
new \fsmaker\Command\Worker\WorkerCommand(),
];
}
diff --git a/src/Web/public/index.html b/src/Web/public/index.html
new file mode 100644
index 0000000..8e6be70
--- /dev/null
+++ b/src/Web/public/index.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+ fsmaker web
+
+
+
+
+
+
+
+
+
diff --git a/src/Web/router.php b/src/Web/router.php
new file mode 100644
index 0000000..70b5927
--- /dev/null
+++ b/src/Web/router.php
@@ -0,0 +1,49 @@
+request->get('command');
+if ($command) {
+ switch ($command) {
+ case 'crear-modelo':
+
+ $nombreModelo = $request->request->get('nombreModelo');
+ $nombreTabla = $request->request->get('nombreTabla');
+
+ $fields[] = new Column([
+ 'nombre' => 'campo1',
+ 'tipo' => 'character varying',
+ 'longitud' => 50
+ ]);
+
+
+ $filePath = getcwd() . '/' . (Utils::isCoreFolder() ? 'Core/Model/' : 'Model/');
+ $filePath = str_replace('/', DIRECTORY_SEPARATOR, $filePath);
+ $fileName = $filePath . $nombreModelo . '.php';
+ Utils::createFolder($filePath);
+ if (file_exists($fileName)) {
+ // TODO devolver error por ajax
+ }
+
+ FileGenerator::createModelByFields($fileName, $nombreTabla, $fields, $nombreModelo, Utils::getNamespace());
+
+ $response->setContent(json_encode(['success' => true]));
+ $response->headers->set('Content-Type', 'application/json');
+ $response->send();
+ return;
+ }
+}
+
+$response->setContent(file_get_contents(__DIR__ . '/public/index.html'));
+$response->send();