Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -233,4 +255,4 @@ fsmaker model -vvv # Debug
## 📞 Issues / Feedback

- 💬 **Contacto**: https://facturascripts.com/contacto
- 🐛 **GitHub**: https://github.com/facturascripts/fsmaker
- 🐛 **GitHub**: https://github.com/facturascripts/fsmaker
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
54 changes: 54 additions & 0 deletions src/Command/Web/WebCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
namespace fsmaker\Command\Web;

use fsmaker\Console\BaseCommand;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'web', description: 'Inicia una interfaz web local')]
class WebCommand extends BaseCommand
{
protected function configure(): void
{
$this
->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('<error>Router no encontrado.</error>');
return Command::FAILURE;
}

$url = "http://$host:$port";
$output->writeln("<info>Servidor iniciado:</info> <comment>$url</comment> — 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 &"),
};
}
}
1 change: 1 addition & 0 deletions src/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
];
}
Expand Down
59 changes: 59 additions & 0 deletions src/Web/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>fsmaker web</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
</head>
<body>
<div class="container mt-5">
<h1>fsmaker web</h1>

<div class="card my-3">
<div class="card-header">
Crear modelo
</div>
<div class="card-body">
<form id="crearModeloForm">
<div class="mb-3">
<input type="text" class="form-control" name="nombreModelo" placeholder="Nombre del modelo" autocomplete="off">
</div>
<div class="mb-3">
<input type="text" class="form-control" name="nombreTabla" placeholder="Nombre de la tabla" autocomplete="off">
</div>
</form>
<button class="btn btn-primary" onclick="runCommand('crear-modelo')">Crear modelo</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
<script>
async function runCommand(command) {
try {
const formData = new FormData(document.getElementById('crearModeloForm'));
formData.append('command', command);

const res = await fetch('/', {
method: 'POST',
body: formData
});

const data = await res.json();

if (!res.ok) {
console.error(data, res);
return;
}

console.log(data);
} catch (err) {
console.error(err);
} finally {
// TODO
}
}
</script>
</body>
</html>

49 changes: 49 additions & 0 deletions src/Web/router.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);

$projectRoot = dirname(__DIR__, 2);
require $projectRoot . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';

use fsmaker\Column;
use fsmaker\FileGenerator;
use fsmaker\Utils;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();
$response = new Response();

$command = $request->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();
Loading