First Commit
This commit is contained in:
+41
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class ActivityLogsClearCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'logs:activity-clear';
|
||||
protected static $defaultDescription = 'Limpa todos os registros da tabela activity_logs';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setHelp('Este comando executa um TRUNCATE na tabela activity_logs para remover todo o histórico de atividades.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
/** @var \Symfony\Component\Console\Helper\QuestionHelper $helper */
|
||||
$helper = $this->getHelper('question');
|
||||
$question = new ConfirmationQuestion('Tem certeza que deseja limpar TODOS os logs de atividade? (y/n) [n]: ', false);
|
||||
|
||||
if (!$helper->ask($input, $output, $question)) {
|
||||
$output->writeln('<info>Operação cancelada.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
try {
|
||||
Capsule::table('activity_logs')->truncate();
|
||||
$output->writeln('<info>Tabela activity_logs limpa com sucesso!</info>');
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln('<error>Erro ao limpar logs: ' . $e->getMessage() . '</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Kernel\Application;
|
||||
|
||||
class AppAboutCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'app:about';
|
||||
protected static $defaultDescription = 'Exibe informações detalhadas sobre a aplicação';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('<info>Sobre a Aplicação SysCMS</info>');
|
||||
$output->writeln('===========================');
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Informação', 'Valor']);
|
||||
|
||||
$table->addRow(['Nome', $_ENV['APP_NAME'] ?? 'SysCMS']);
|
||||
$table->addRow(['Versão', '1.0.0']);
|
||||
$table->addRow(['Ambiente', $_ENV['APP_ENV'] ?? 'local']);
|
||||
$table->addRow(['Debug', ($_ENV['APP_DEBUG'] ?? 'false') === 'true' ? '<info>Ativo</info>' : '<comment>Inativo</comment>']);
|
||||
$table->addRow(['URL', $_ENV['APP_URL'] ?? 'http://localhost']);
|
||||
$table->addRow(['PHP Version', PHP_VERSION]);
|
||||
$table->addRow(['OS', PHP_OS]);
|
||||
$table->addRow(['Database', $_ENV['DB_DATABASE'] ?? 'syscms']);
|
||||
$table->addRow(['Database Driver', $_ENV['DB_CONNECTION'] ?? 'mysql']);
|
||||
$table->addRow(['Timezone', date_default_timezone_get()]);
|
||||
$table->addRow(['Locale', $_SESSION['lang'] ?? 'pt_BR']);
|
||||
|
||||
$table->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class AppInfoCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'app:info';
|
||||
protected static $defaultDescription = 'Displays application information';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln([
|
||||
'<info>SysCMS - PHP Content Management System</info>',
|
||||
'========================================',
|
||||
'',
|
||||
]);
|
||||
|
||||
$output->writeln("PHP Version: " . PHP_VERSION);
|
||||
$output->writeln("Environment: " . ($_ENV['APP_ENV'] ?? 'production'));
|
||||
$output->writeln("Debug Mode: " . (($_ENV['APP_DEBUG'] ?? 'false') === 'true' ? 'Enabled' : 'Disabled'));
|
||||
$output->writeln("URL: " . ($_ENV['APP_URL'] ?? 'Not set'));
|
||||
|
||||
$output->writeln([
|
||||
'',
|
||||
'<comment>Database:</comment>',
|
||||
"Connection: " . ($_ENV['DB_CONNECTION'] ?? 'mysql'),
|
||||
"Host: " . ($_ENV['DB_HOST'] ?? 'localhost'),
|
||||
"Database: " . ($_ENV['DB_DATABASE'] ?? 'syscms'),
|
||||
]);
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
|
||||
class AppOptimizeCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'app:optimize';
|
||||
protected static $defaultDescription = 'Otimiza a aplicação limpando caches e bancos de dados (comandos combinados)';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('<info>Iniciando otimização completa do sistema...</info>');
|
||||
|
||||
// 1. Clear Cache
|
||||
$output->writeln("\n<comment>Limpando caches...</comment>");
|
||||
$cacheCommand = $this->getApplication()->find('cache:clear');
|
||||
$cacheCommand->run(new ArrayInput([]), $output);
|
||||
|
||||
// 2. Clear Logs
|
||||
$output->writeln("\n<comment>Limpando logs...</comment>");
|
||||
$logsCommand = $this->getApplication()->find('logs:clear');
|
||||
$logsCommand->run(new ArrayInput([]), $output);
|
||||
|
||||
// 3. Optimize DB
|
||||
$output->writeln("\n<comment>Otimizando banco de dados...</comment>");
|
||||
$dbCommand = $this->getApplication()->find('db:optimize');
|
||||
$dbCommand->run(new ArrayInput([]), $output);
|
||||
|
||||
$output->writeln("\n<info>Aplicação otimizada com sucesso!</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class AppRenameCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'app:rename';
|
||||
protected static $defaultDescription = 'Altera o nome da aplicação no arquivo .env';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O novo nome da aplicação');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$newName = $input->getArgument('name');
|
||||
$envFile = dirname(__DIR__, 3) . '/.env';
|
||||
|
||||
if (!file_exists($envFile)) {
|
||||
$output->writeln('<error>Arquivo .env não encontrado.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$content = file_get_contents($envFile);
|
||||
$pattern = "/APP_NAME=(.*)/";
|
||||
$replacement = "APP_NAME=\"{$newName}\"";
|
||||
|
||||
if (preg_match($pattern, $content)) {
|
||||
$newContent = preg_replace($pattern, $replacement, $content);
|
||||
} else {
|
||||
$newContent = $content . "\nAPP_NAME=\"{$newName}\"";
|
||||
}
|
||||
|
||||
if (file_put_contents($envFile, $newContent)) {
|
||||
$output->writeln("<info>Aplicação renomeada para '{$newName}' com sucesso!</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$output->writeln('<error>Falha ao renomear a aplicação.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
Executable
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class CacheClearCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'cache:clear';
|
||||
protected static $defaultDescription = 'Clears the application cache';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('Clearing cache...');
|
||||
|
||||
$cacheDirs = [
|
||||
dirname(__DIR__, 3) . '/cache/twig',
|
||||
// Add other cache directories here
|
||||
];
|
||||
|
||||
$hasError = false;
|
||||
|
||||
foreach ($cacheDirs as $dir) {
|
||||
if (is_dir($dir)) {
|
||||
$output->write("Limpando <info>{$dir}</info>... ");
|
||||
if ($this->deleteDirectory($dir)) {
|
||||
$output->writeln('<info>OK</info>');
|
||||
// Recreate empty directory
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0777, true);
|
||||
chmod($dir, 0777);
|
||||
}
|
||||
} else {
|
||||
$output->writeln('<error>FALHA</error>');
|
||||
$hasError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasError) {
|
||||
$output->writeln('<error>Alguns caches não puderam ser limpos.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$output->writeln('<info>Cache limpo com sucesso!</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function deleteDirectory($dir) {
|
||||
if (!file_exists($dir)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_dir($dir)) {
|
||||
return unlink($dir);
|
||||
}
|
||||
|
||||
foreach (scandir($dir) as $item) {
|
||||
if ($item == '.' || $item == '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return rmdir($dir);
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) 2025 Marco Costa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Marco Costa
|
||||
* Email: contato@syspanel.com.br
|
||||
* Project: SysCMS
|
||||
*
|
||||
* This software is licensed, not sold.
|
||||
* Permission is granted to use this software
|
||||
* subject to the terms of the SysCMS Commercial License.
|
||||
*
|
||||
* Redistribution, sublicensing, resale, or
|
||||
* disclosure of this software, in whole or in part,
|
||||
* is strictly prohibited without prior written permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Modules\Auth\Models\User;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class CreateSuperAdminCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'user:create-super-admin';
|
||||
protected static $defaultDescription = 'Creates the default Super Admin user';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$email = 'superadmin@syscms.com';
|
||||
$password = 'SuperAdmin123!';
|
||||
|
||||
try {
|
||||
// Remove global scopes to ensure we can find the user regardless of company context
|
||||
$user = User::withoutGlobalScopes()->where('users_email', $email)->first();
|
||||
|
||||
if ($user) {
|
||||
$user->users_role = 'super_admin';
|
||||
$user->users_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$user->users_status = 'active';
|
||||
$user->save();
|
||||
$output->writeln('<info>Usuário Super Admin atualizado com sucesso!</info>');
|
||||
} else {
|
||||
$user = new User();
|
||||
$user->users_name = 'Super Admin';
|
||||
$user->users_email = $email;
|
||||
$user->users_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$user->users_role = 'super_admin';
|
||||
$user->users_status = 'active';
|
||||
$user->save();
|
||||
$output->writeln('<info>Usuário Super Admin criado com sucesso!</info>');
|
||||
}
|
||||
|
||||
$output->writeln([
|
||||
'',
|
||||
'Credenciais:',
|
||||
"Email: $email",
|
||||
"Senha: $password",
|
||||
"Role: super_admin",
|
||||
''
|
||||
]);
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Modules\Auth\Models\User;
|
||||
|
||||
class CreateUserCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'user:create';
|
||||
protected static $defaultDescription = 'Creates a new user';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('email', InputArgument::OPTIONAL, 'User email');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
// Email
|
||||
$email = $input->getArgument('email');
|
||||
if (!$email) {
|
||||
$question = new Question('Email do usuário: ');
|
||||
$email = $helper->ask($input, $output, $question);
|
||||
}
|
||||
|
||||
if (User::where('users_email', $email)->exists()) {
|
||||
$output->writeln("<error>Já existe um usuário com o email {$email}</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
// Name
|
||||
$question = new Question('Nome do usuário: ');
|
||||
$name = $helper->ask($input, $output, $question);
|
||||
|
||||
// Password
|
||||
$question = new Question('Senha: ');
|
||||
$question->setHidden(true);
|
||||
$question->setHiddenFallback(false);
|
||||
$password = $helper->ask($input, $output, $question);
|
||||
|
||||
// Role
|
||||
$question = new Question('Role (padrão: user): ', 'user');
|
||||
$role = $helper->ask($input, $output, $question);
|
||||
|
||||
// Bus ID
|
||||
$question = new Question('ID Bus (opcional): ');
|
||||
$busId = $helper->ask($input, $output, $question);
|
||||
|
||||
try {
|
||||
$user = new User();
|
||||
$user->users_name = $name;
|
||||
$user->users_email = $email;
|
||||
$user->users_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$user->users_role = $role;
|
||||
$user->users_bus_id = $busId;
|
||||
$user->users_status = 'active';
|
||||
$user->save();
|
||||
|
||||
$output->writeln('<info>Usuário criado com sucesso!</info>');
|
||||
$output->writeln("ID: {$user->users_id}");
|
||||
$output->writeln("Nome: {$user->users_name}");
|
||||
$output->writeln("Email: {$user->users_email}");
|
||||
$output->writeln("Role: {$user->users_role}");
|
||||
$output->writeln("ID Bus: " . ($user->users_bus_id ?? '-'));
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro ao criar usuário: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class DbBackupCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:backup';
|
||||
protected static $defaultDescription = 'Cria um backup do banco de dados';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp('Este comando gera um dump SQL do banco de dados atual.')
|
||||
->addOption('path', 'p', InputOption::VALUE_OPTIONAL, 'Diretório para salvar o backup', 'storage/backups')
|
||||
->addOption('compress', 'c', InputOption::VALUE_NONE, 'Comprimir o backup (gzip)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('<info>Iniciando backup do banco de dados...</info>');
|
||||
|
||||
$host = $_ENV['DB_HOST'] ?? 'localhost';
|
||||
$port = $_ENV['DB_PORT'] ?? '3306';
|
||||
$database = $_ENV['DB_DATABASE'] ?? 'syscms';
|
||||
$username = $_ENV['DB_USERNAME'] ?? 'root';
|
||||
$password = $_ENV['DB_PASSWORD'] ?? '';
|
||||
|
||||
$backupDir = $input->getOption('path');
|
||||
|
||||
// Se o caminho for relativo, resolvemos a partir da raiz do projeto
|
||||
if (!str_starts_with($backupDir, '/')) {
|
||||
$backupDir = dirname(__DIR__, 3) . '/' . ltrim($backupDir, '/');
|
||||
}
|
||||
|
||||
if (!is_dir($backupDir)) {
|
||||
if (!mkdir($backupDir, 0755, true)) {
|
||||
$output->writeln("<error>Não foi possível criar o diretório de backup: {$backupDir}</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
$filename = $database . '_' . date('Y-m-d_H-i-s') . '.sql';
|
||||
$fullPath = rtrim($backupDir, '/') . '/' . $filename;
|
||||
|
||||
// Escapamos a senha para o shell
|
||||
$escapedPassword = escapeshellarg($password);
|
||||
|
||||
// Usamos mysqldump para criar o backup
|
||||
// Note: Se o mysqldump não estiver no PATH, este comando pode falhar
|
||||
$command = "mysqldump --host={$host} --port={$port} --user={$username} --password={$escapedPassword} {$database} > " . escapeshellarg($fullPath);
|
||||
|
||||
if ($input->getOption('compress')) {
|
||||
$command .= " && gzip " . escapeshellarg($fullPath);
|
||||
$fullPath .= '.gz';
|
||||
}
|
||||
|
||||
exec($command . " 2>&1", $outputArray, $resultCode);
|
||||
|
||||
if ($resultCode === 0) {
|
||||
$output->writeln("<info>Backup concluído com sucesso: {$fullPath}</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Erro ao realizar o backup (Código: {$resultCode}).</error>");
|
||||
$output->writeln("<error>Saída: " . implode("\n", $outputArray) . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class DbExportCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:export';
|
||||
protected static $defaultDescription = 'Exporta os dados de uma tabela para CSV ou JSON';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('table', InputArgument::REQUIRED, 'O nome da tabela')
|
||||
->addOption('format', 'f', InputOption::VALUE_OPTIONAL, 'O formato do arquivo (csv, json)', 'csv')
|
||||
->addOption('path', 'p', InputOption::VALUE_OPTIONAL, 'O caminho para salvar o arquivo', 'storage/exports');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$tableName = $input->getArgument('table');
|
||||
$format = strtolower($input->getOption('format'));
|
||||
$path = $input->getOption('path');
|
||||
|
||||
$connection = Capsule::connection();
|
||||
$dbName = $connection->getDatabaseName();
|
||||
|
||||
if (!Capsule::schema()->hasTable($tableName)) {
|
||||
$output->writeln("<error>Tabela '{$tableName}' não encontrada no banco de dados.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$results = $connection->table($tableName)->get();
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
$output->writeln("<info>A tabela '{$tableName}' está vazia.</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$output->writeln("<info>Exportando dados da tabela: {$tableName}</info>");
|
||||
|
||||
$directory = dirname(__DIR__, 3) . '/' . ltrim($path, '/');
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$filename = "{$tableName}_" . date('Y-m-d_H-i-s') . ".{$format}";
|
||||
$fullPath = rtrim($directory, '/') . '/' . $filename;
|
||||
|
||||
if ($format === 'json') {
|
||||
file_put_contents($fullPath, json_encode($results, JSON_PRETTY_PRINT));
|
||||
} elseif ($format === 'csv') {
|
||||
$fp = fopen($fullPath, 'w');
|
||||
|
||||
// Adiciona o cabeçalho
|
||||
$headers = array_keys((array) $results[0]);
|
||||
fputcsv($fp, $headers);
|
||||
|
||||
foreach ($results as $row) {
|
||||
fputcsv($fp, (array) $row);
|
||||
}
|
||||
|
||||
fclose($fp);
|
||||
} else {
|
||||
$output->writeln("<error>Formato '{$format}' não suportado.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$output->writeln("<info>Dados exportados com sucesso para: {$fullPath}</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+108
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class DbImportCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:import';
|
||||
protected static $defaultDescription = 'Importa um arquivo SQL para o banco de dados';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('file', InputArgument::REQUIRED, 'O caminho do arquivo SQL a ser importado');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$file = $input->getArgument('file');
|
||||
|
||||
if (!file_exists($file)) {
|
||||
$output->writeln("<error>Arquivo não encontrado: {$file}</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$output->writeln("<info>Importando arquivo: {$file}</info>");
|
||||
|
||||
try {
|
||||
$sql = file_get_contents($file);
|
||||
if (!$sql) {
|
||||
$output->writeln("<error>Falha ao ler o arquivo SQL ou arquivo vazio.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$connection = Capsule::connection();
|
||||
$queries = $this->splitSqlQueries($sql);
|
||||
$totalQueries = count($queries);
|
||||
$successCount = 0;
|
||||
|
||||
$output->writeln("<comment>Total de queries encontradas: {$totalQueries}</comment>");
|
||||
|
||||
foreach ($queries as $index => $query) {
|
||||
$query = trim($query);
|
||||
if (empty($query)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$connection->statement($query);
|
||||
$successCount++;
|
||||
$output->writeln("<info>Query " . ($index + 1) . "/{$totalQueries} executada com sucesso</info>");
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro na query " . ($index + 1) . ": " . $e->getMessage() . "</error>");
|
||||
$output->writeln("<comment>Query: " . substr($query, 0, 100) . "...</comment>");
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln("<info>Importação concluída. {$successCount}/{$totalQueries} queries executadas com sucesso.</info>");
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro ao importar arquivo: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
private function splitSqlQueries(string $sql): array
|
||||
{
|
||||
$queries = [];
|
||||
$current = '';
|
||||
$inString = false;
|
||||
$stringChar = '';
|
||||
$length = strlen($sql);
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$char = $sql[$i];
|
||||
|
||||
if (($char === "'" || $char === '"') && ($i === 0 || $sql[$i - 1] !== '\\')) {
|
||||
if (!$inString) {
|
||||
$inString = true;
|
||||
$stringChar = $char;
|
||||
} elseif ($char === $stringChar) {
|
||||
$inString = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$inString && $char === ';') {
|
||||
$queries[] = trim($current);
|
||||
$current = '';
|
||||
} else {
|
||||
$current .= $char;
|
||||
}
|
||||
}
|
||||
|
||||
$current = trim($current);
|
||||
if (!empty($current)) {
|
||||
$queries[] = $current;
|
||||
}
|
||||
|
||||
return array_filter($queries, function($query) {
|
||||
return !empty(trim($query));
|
||||
});
|
||||
}
|
||||
}
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
class DbListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:list';
|
||||
protected static $defaultDescription = 'Lista todas as tabelas do banco de dados';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$connection = Capsule::connection();
|
||||
$dbName = $connection->getDatabaseName();
|
||||
|
||||
$output->writeln("<info>Tabelas no banco de dados: {$dbName}</info>");
|
||||
|
||||
$tables = $connection->select('SHOW TABLES');
|
||||
$key = "Tables_in_{$dbName}";
|
||||
|
||||
if (empty($tables)) {
|
||||
$output->writeln('<info>Nenhuma tabela encontrada no banco de dados.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Tabela', 'Total de Registros']);
|
||||
|
||||
foreach ($tables as $t) {
|
||||
$tableName = $t->$key;
|
||||
$count = $connection->table($tableName)->count();
|
||||
$table->addRow([$tableName, $count]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
$output->writeln("<info>Total de tabelas: " . count($tables) . "</info>");
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
class DbMonitorCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:monitor';
|
||||
protected static $defaultDescription = 'Monitora o status atual do banco de dados e processos ativos';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$connection = Capsule::connection();
|
||||
$dbName = $connection->getDatabaseName();
|
||||
|
||||
$output->writeln("<info>Monitorando banco de dados: {$dbName}</info>");
|
||||
$output->writeln("===============================================");
|
||||
|
||||
// Active processes
|
||||
$processes = $connection->select('SHOW PROCESSLIST');
|
||||
$output->writeln("<comment>Processos Ativos:</comment>");
|
||||
$processTable = new Table($output);
|
||||
$processTable->setHeaders(['ID', 'User', 'Host', 'Command', 'Time', 'State', 'Info']);
|
||||
|
||||
foreach ($processes as $p) {
|
||||
$processTable->addRow([
|
||||
$p->Id,
|
||||
$p->User,
|
||||
$p->Host,
|
||||
$p->Command,
|
||||
$p->Time,
|
||||
$p->State,
|
||||
substr($p->Info ?? '', 0, 50) . (strlen($p->Info ?? '') > 50 ? '...' : '')
|
||||
]);
|
||||
}
|
||||
$processTable->render();
|
||||
|
||||
$output->writeln("");
|
||||
|
||||
// Database status variables
|
||||
$status = $connection->select("SHOW STATUS WHERE Variable_name IN ('Threads_connected', 'Threads_running', 'Uptime', 'Questions')");
|
||||
$output->writeln("<comment>Variáveis de Status:</comment>");
|
||||
$statusTable = new Table($output);
|
||||
$statusTable->setHeaders(['Variável', 'Valor']);
|
||||
|
||||
foreach ($status as $s) {
|
||||
$statusTable->addRow([$s->Variable_name, $s->Value]);
|
||||
}
|
||||
$statusTable->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class DbOptimizeCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:optimize';
|
||||
protected static $defaultDescription = 'Otimiza as tabelas do banco de dados';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$connection = Capsule::connection();
|
||||
$dbName = $connection->getDatabaseName();
|
||||
|
||||
$output->writeln("<info>Otimizando banco de dados: {$dbName}</info>");
|
||||
|
||||
$tables = $connection->select('SHOW TABLES');
|
||||
$key = "Tables_in_{$dbName}";
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$tableName = $table->$key;
|
||||
$output->write("Otimizando tabela: <comment>{$tableName}</comment>... ");
|
||||
|
||||
try {
|
||||
$connection->statement("OPTIMIZE TABLE {$tableName}");
|
||||
$output->writeln('<info>OK</info>');
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln('<error>Erro ao otimizar</error>');
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('<info>Otimização concluída!</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
class DbQueryCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:query';
|
||||
protected static $defaultDescription = 'Executa uma query SQL diretamente no banco de dados';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('query', InputArgument::REQUIRED, 'A query SQL a ser executada');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$query = $input->getArgument('query');
|
||||
$connection = Capsule::connection();
|
||||
|
||||
$output->writeln("<info>Executando query:</info> <comment>{$query}</comment>");
|
||||
|
||||
try {
|
||||
if (stripos($query, 'select') === 0 || stripos($query, 'show') === 0 || stripos($query, 'describe') === 0) {
|
||||
$results = $connection->select($query);
|
||||
|
||||
if (empty($results)) {
|
||||
$output->writeln('<info>Nenhum resultado encontrado.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
$headers = array_keys((array) $results[0]);
|
||||
$table->setHeaders($headers);
|
||||
|
||||
foreach ($results as $row) {
|
||||
$table->addRow((array) $row);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
$output->writeln("<info>Total de registros: " . count($results) . "</info>");
|
||||
} else {
|
||||
$affected = $connection->affectingStatement($query);
|
||||
$output->writeln("<info>Query executada com sucesso. Linhas afetadas: {$affected}</info>");
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro ao executar query: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
class DbRelationshipsCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:relationships';
|
||||
protected static $defaultDescription = 'Exibe as chaves estrangeiras de uma tabela';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('table', InputArgument::REQUIRED, 'O nome da tabela');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$tableName = $input->getArgument('table');
|
||||
$connection = Capsule::connection();
|
||||
$dbName = $connection->getDatabaseName();
|
||||
|
||||
$output->writeln("<info>Chaves Estrangeiras da Tabela: {$tableName}</info>");
|
||||
|
||||
try {
|
||||
$query = "
|
||||
SELECT
|
||||
COLUMN_NAME,
|
||||
CONSTRAINT_NAME,
|
||||
REFERENCED_TABLE_NAME,
|
||||
REFERENCED_COLUMN_NAME
|
||||
FROM
|
||||
INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
||||
WHERE
|
||||
TABLE_SCHEMA = ? AND
|
||||
TABLE_NAME = ? AND
|
||||
REFERENCED_TABLE_NAME IS NOT NULL";
|
||||
|
||||
$relationships = $connection->select($query, [$dbName, $tableName]);
|
||||
|
||||
if (empty($relationships)) {
|
||||
$output->writeln('<comment>Nenhuma chave estrangeira encontrada para esta tabela.</comment>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Coluna', 'Constraint', 'Tabela Referenciada', 'Coluna Referenciada']);
|
||||
|
||||
foreach ($relationships as $rel) {
|
||||
$table->addRow([
|
||||
$rel->COLUMN_NAME,
|
||||
$rel->CONSTRAINT_NAME,
|
||||
$rel->REFERENCED_TABLE_NAME,
|
||||
$rel->REFERENCED_COLUMN_NAME
|
||||
]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro ao buscar relacionamentos: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class DbSeedCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:seed';
|
||||
protected static $defaultDescription = 'Executa as classes de seeder';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('class', InputArgument::OPTIONAL, 'O nome da classe seeder específica para rodar');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$className = $input->getArgument('class');
|
||||
$seedersPath = dirname(__DIR__, 3) . '/database/seeders';
|
||||
|
||||
if (!is_dir($seedersPath)) {
|
||||
$output->writeln('<error>Diretório de seeders não encontrado.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if ($className) {
|
||||
return $this->runSeeder($className, $seedersPath, $output);
|
||||
}
|
||||
|
||||
// Se não especificou classe, tenta rodar o DatabaseSeeder ou todos os arquivos .php
|
||||
$dbSeederFile = $seedersPath . '/DatabaseSeeder.php';
|
||||
if (file_exists($dbSeederFile)) {
|
||||
return $this->runSeeder('DatabaseSeeder', $seedersPath, $output);
|
||||
}
|
||||
|
||||
$files = glob($seedersPath . '/*.php');
|
||||
if (empty($files)) {
|
||||
$output->writeln('<info>Nenhum seeder encontrado.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
$name = basename($file, '.php');
|
||||
if ($name === 'DatabaseSeeder') continue; // Já rodamos se existisse
|
||||
$this->runSeeder($name, $seedersPath, $output);
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function runSeeder(string $name, string $path, OutputInterface $output): int
|
||||
{
|
||||
$file = $path . '/' . $name . '.php';
|
||||
|
||||
if (!file_exists($file)) {
|
||||
$output->writeln("<error>Seeder não encontrado: {$name}</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$output->write("Rodando seeder: <info>{$name}</info>... ");
|
||||
|
||||
try {
|
||||
require_once $file;
|
||||
|
||||
if (class_exists($name)) {
|
||||
$seeder = new $name();
|
||||
if (method_exists($seeder, 'run')) {
|
||||
$seeder->run();
|
||||
$output->writeln('<info>OK</info>');
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln('<comment>Método run() não encontrado.</comment>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
} else {
|
||||
$output->writeln("<error>Classe {$name} não encontrada no arquivo.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>FALHA</error>");
|
||||
$output->writeln("<error>Erro: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
class DbShowCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:show';
|
||||
protected static $defaultDescription = 'Exibe informações sobre o banco de dados';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$connection = Capsule::connection();
|
||||
$dbName = $connection->getDatabaseName();
|
||||
|
||||
$output->writeln("<info>Banco de Dados: {$dbName}</info>");
|
||||
$output->writeln("Driver: " . $connection->getDriverName());
|
||||
|
||||
$tables = $connection->select('SHOW TABLE STATUS');
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Tabela', 'Engine', 'Rows', 'Size (MB)', 'Collation']);
|
||||
|
||||
foreach ($tables as $t) {
|
||||
$size = round(($t->Data_length + $t->Index_length) / 1024 / 1024, 2);
|
||||
$table->addRow([
|
||||
$t->Name,
|
||||
$t->Engine,
|
||||
$t->Rows,
|
||||
$size,
|
||||
$t->Collation
|
||||
]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class DbSyncSisTablesCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:sync-sis-tables';
|
||||
protected static $defaultDescription = 'Substitui as tabelas sis_*** no evoluterSys2.sql pelas tabelas de syscms.sql';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$targetFile = 'evoluterSys2.sql';
|
||||
$sourceFile = 'syscms.sql';
|
||||
|
||||
if (!file_exists($targetFile)) {
|
||||
$output->writeln("<error>Arquivo de destino não encontrado: $targetFile</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!file_exists($sourceFile)) {
|
||||
$output->writeln("<error>Arquivo de origem não encontrado: $sourceFile</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$output->writeln("<info>Iniciando a extração das tabelas sis_*** de $sourceFile...</info>");
|
||||
$sisTablesDefinitions = $this->extractSisTables($sourceFile);
|
||||
|
||||
if (empty($sisTablesDefinitions)) {
|
||||
$output->writeln("<error>Nenhuma tabela sis_*** encontrada em $sourceFile.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$output->writeln("<info>Encontradas " . count($sisTablesDefinitions) . " tabelas sis_***. Substituindo em $targetFile...</info>");
|
||||
$this->replaceSisTables($targetFile, $sisTablesDefinitions, $output);
|
||||
|
||||
$output->writeln("<info>Operação concluída com sucesso!</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function extractSisTables(string $filePath): array
|
||||
{
|
||||
$handle = fopen($filePath, 'r');
|
||||
if (!$handle) return [];
|
||||
|
||||
$tables = [];
|
||||
$currentTable = null;
|
||||
$capture = false;
|
||||
$buffer = "";
|
||||
|
||||
while (($line = fgets($handle)) !== false) {
|
||||
// Detecta início de um CREATE TABLE sis_***
|
||||
if (preg_match("/CREATE TABLE `?(sis_[^`\s(]+)`?/i", $line, $matches)) {
|
||||
$currentTable = $matches[1];
|
||||
$capture = true;
|
||||
$buffer = $line;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($capture) {
|
||||
$buffer .= $line;
|
||||
// Detecta fim do CREATE TABLE (assume-se que termina com ); ou ); seguido de comentários/inserts se for dump compactado,
|
||||
// mas para simplificar, buscamos o padrão );
|
||||
if (preg_match("/\);/", $line)) {
|
||||
$capture = false;
|
||||
$tables[$currentTable] = $buffer;
|
||||
$buffer = "";
|
||||
$currentTable = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
return $tables;
|
||||
}
|
||||
|
||||
private function replaceSisTables(string $filePath, array $definitions, OutputInterface $output): void
|
||||
{
|
||||
$tempFile = $filePath . '.tmp';
|
||||
$inHandle = fopen($filePath, 'r');
|
||||
$outHandle = fopen($tempFile, 'w');
|
||||
|
||||
$skip = false;
|
||||
$replacedCount = 0;
|
||||
|
||||
while (($line = fgets($inHandle)) !== false) {
|
||||
// Verifica se a linha inicia uma tabela que queremos substituir
|
||||
if (preg_match("/CREATE TABLE `?(sis_[^`\s(]+)`?/i", $line, $matches)) {
|
||||
$tableName = $matches[1];
|
||||
if (isset($definitions[$tableName])) {
|
||||
$output->writeln("Substituindo tabela: <comment>$tableName</comment>");
|
||||
fwrite($outHandle, $definitions[$tableName]);
|
||||
$skip = true;
|
||||
$replacedCount++;
|
||||
unset($definitions[$tableName]); // Marca como usada
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Se estiver pulando, ignora as linhas até o fim da definição da tabela
|
||||
if ($skip) {
|
||||
if (preg_match("/\);/", $line)) {
|
||||
$skip = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
fwrite($outHandle, $line);
|
||||
}
|
||||
|
||||
// Se sobraram tabelas no source que não existiam no target, podemos adicioná-las ao final ou apenas informar
|
||||
if (!empty($definitions)) {
|
||||
$output->writeln("<info>Adicionando novas tabelas sis_*** que não existiam no destino...</info>");
|
||||
foreach ($definitions as $tableName => $def) {
|
||||
$output->writeln("Adicionando: <comment>$tableName</comment>");
|
||||
fwrite($outHandle, "\n" . $def . "\n");
|
||||
$replacedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
fclose($inHandle);
|
||||
fclose($outHandle);
|
||||
|
||||
rename($tempFile, $filePath);
|
||||
$output->writeln("<info>Total de tabelas processadas: $replacedCount</info>");
|
||||
}
|
||||
}
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
class DbTableCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:table';
|
||||
protected static $defaultDescription = 'Exibe a estrutura de uma tabela específica';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('table', InputArgument::REQUIRED, 'O nome da tabela');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$tableName = $input->getArgument('table');
|
||||
$connection = Capsule::connection();
|
||||
|
||||
try {
|
||||
$columns = $connection->select("SHOW COLUMNS FROM {$tableName}");
|
||||
|
||||
$output->writeln("<info>Estrutura da tabela: {$tableName}</info>");
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Field', 'Type', 'Null', 'Key', 'Default', 'Extra']);
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$table->addRow([
|
||||
$column->Field,
|
||||
$column->Type,
|
||||
$column->Null,
|
||||
$column->Key,
|
||||
$column->Default,
|
||||
$column->Extra
|
||||
]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Tabela '{$tableName}' não encontrada ou erro na query.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class DbWipeCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'db:wipe';
|
||||
protected static $defaultDescription = 'Drop all tables, views, and types';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp('This command drops all tables from the database without removing the database itself.')
|
||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Force the operation to run');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (!$input->getOption('force')) {
|
||||
$output->writeln('<error>Atenção: Este comando irá apagar TODAS as tabelas do banco de dados!</error>');
|
||||
$output->writeln('<comment>Use a opção --force para confirmar.</comment>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$output->writeln('<info>Limpando banco de dados...</info>');
|
||||
|
||||
$schema = Capsule::schema();
|
||||
$tables = Capsule::connection()->select('SHOW FULL TABLES WHERE Table_type = "BASE TABLE"');
|
||||
$dbName = Capsule::connection()->getDatabaseName();
|
||||
$key = "Tables_in_{$dbName}";
|
||||
|
||||
Capsule::connection()->statement('SET FOREIGN_KEY_CHECKS = 0');
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$tableName = $table->$key;
|
||||
$output->write("Dropando tabela: <comment>{$tableName}</comment>... ");
|
||||
$schema->drop($tableName);
|
||||
$output->writeln('<info>OK</info>');
|
||||
}
|
||||
|
||||
Capsule::connection()->statement('SET FOREIGN_KEY_CHECKS = 1');
|
||||
|
||||
$output->writeln('<info>Banco de dados limpo com sucesso!</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Kernel\Application;
|
||||
|
||||
class DebugContainerCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'debug:container';
|
||||
protected static $defaultDescription = 'Lista todos os serviços registrados no container de injeção de dependência';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$app = Application::getInstance();
|
||||
if (!$app) {
|
||||
$output->writeln('<error>Não foi possível obter a instância da aplicação.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$container = $app->getContainer();
|
||||
|
||||
// PHP-DI doesn't easily expose all registered definitions unless we use internal reflection
|
||||
// or a specific configuration. For simplicity in this environment, we'll list what's common.
|
||||
|
||||
$output->writeln('<info>Serviços no Container DI:</info>');
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['ID', 'Status']);
|
||||
|
||||
$commonServices = [
|
||||
\DI\Container::class,
|
||||
\Kernel\Application::class,
|
||||
\Kernel\ModuleLoader::class,
|
||||
\Kernel\View::class,
|
||||
'db',
|
||||
'logging',
|
||||
'mailer'
|
||||
];
|
||||
|
||||
foreach ($commonServices as $service) {
|
||||
$status = $container->has($service) ? '<info>Registrado</info>' : '<comment>Não definido</comment>';
|
||||
$table->addRow([$service, $status]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Kernel\Application;
|
||||
|
||||
class DebugRouterCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'debug:router';
|
||||
protected static $defaultDescription = 'Lista detalhes das rotas registradas na aplicação';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$app = Application::getInstance();
|
||||
if (!$app) {
|
||||
$output->writeln('<error>Não foi possível obter a instância da aplicação.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$routes = $app->getRoutes();
|
||||
|
||||
$output->writeln('<info>Rotas Registradas:</info>');
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Método', 'Caminho', 'Handler']);
|
||||
|
||||
foreach ($routes as $route) {
|
||||
[$method, $path, $handler] = $route;
|
||||
|
||||
$handlerStr = is_array($handler) ? implode('@', $handler) : 'Closure';
|
||||
$table->addRow([$method, $path, $handlerStr]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class DownCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'down';
|
||||
protected static $defaultDescription = 'Coloca a aplicação em modo de manutenção';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('message', 'm', InputOption::VALUE_OPTIONAL, 'A mensagem a ser exibida durante a manutenção', 'O sistema está em manutenção.')
|
||||
->addOption('retry', 'r', InputOption::VALUE_OPTIONAL, 'O tempo estimado para o retorno');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$directory = dirname(__DIR__, 3) . '/storage/framework';
|
||||
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$downFile = $directory . '/down';
|
||||
|
||||
if (file_exists($downFile)) {
|
||||
$output->writeln('<comment>A aplicação já está em modo de manutenção.</comment>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'time' => time(),
|
||||
'message' => $input->getOption('message'),
|
||||
'retry' => $input->getOption('retry'),
|
||||
];
|
||||
|
||||
if (file_put_contents($downFile, json_encode($payload, JSON_PRETTY_PRINT))) {
|
||||
$output->writeln('<info>Aplicação agora está em modo de manutenção.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$output->writeln('<error>Falha ao colocar a aplicação em modo de manutenção.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
class EnvListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'env:list';
|
||||
protected static $defaultDescription = 'Lista as variáveis de ambiente carregadas do .env';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('<info>Variáveis de Ambiente (.env):</info>');
|
||||
|
||||
$envFile = dirname(__DIR__, 3) . '/.env';
|
||||
|
||||
if (!file_exists($envFile)) {
|
||||
$output->writeln('<error>Arquivo .env não encontrado.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Variável', 'Valor']);
|
||||
|
||||
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
// Ignorar comentários
|
||||
if (str_starts_with(trim($line), '#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_contains($line, '=')) {
|
||||
[$key, $value] = explode('=', $line, 2);
|
||||
|
||||
// Ocultar senhas e chaves sensíveis por segurança
|
||||
if (preg_match('/(PASSWORD|SECRET|KEY|TOKEN)/i', $key)) {
|
||||
$value = '********';
|
||||
}
|
||||
|
||||
$table->addRow([trim($key), trim($value, '"\' ')]);
|
||||
}
|
||||
}
|
||||
|
||||
$table->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class KeyGenerateCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'key:generate';
|
||||
protected static $defaultDescription = 'Gera uma nova chave de aplicação (APP_KEY)';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$key = bin2hex(random_bytes(32));
|
||||
$envFile = dirname(__DIR__, 3) . '/.env';
|
||||
|
||||
if (!file_exists($envFile)) {
|
||||
$output->writeln("<error>Arquivo .env não encontrado.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$content = file_get_contents($envFile);
|
||||
|
||||
if (strpos($content, 'APP_KEY=') !== false) {
|
||||
$content = preg_replace('/APP_KEY=.*/', 'APP_KEY=' . $key, $content);
|
||||
} else {
|
||||
$content .= "\nAPP_KEY=" . $key;
|
||||
}
|
||||
|
||||
if (file_put_contents($envFile, $content)) {
|
||||
$output->writeln("<info>APP_KEY gerada com sucesso!</info>");
|
||||
$output->writeln("<comment>Chave:</comment> {$key}");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao escrever no arquivo .env.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class LogsClearCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'logs:clear';
|
||||
protected static $defaultDescription = 'Limpa os arquivos de log do sistema';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$logDir = dirname(__DIR__, 3) . '/logs';
|
||||
|
||||
if (!is_dir($logDir)) {
|
||||
$output->writeln('<error>Diretório de logs não encontrado.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$files = glob($logDir . '/*.log');
|
||||
|
||||
if (empty($files)) {
|
||||
$output->writeln('<info>Nenhum arquivo de log para limpar.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
$fileName = basename($file);
|
||||
if (unlink($file)) {
|
||||
$output->writeln("<info>Arquivo de log '{$fileName}' removido.</info>");
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao remover o arquivo '{$fileName}'.</error>");
|
||||
}
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeCommandCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:command';
|
||||
protected static $defaultDescription = 'Cria um novo comando para o syscli';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome da classe do comando (ex: TestCommand)')
|
||||
->addArgument('command', InputArgument::REQUIRED, 'O comando a ser digitado (ex: app:test)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$commandName = $input->getArgument('command');
|
||||
|
||||
// Garantir que termina com Command
|
||||
if (!str_ends_with($name, 'Command')) {
|
||||
$name .= 'Command';
|
||||
}
|
||||
|
||||
$commandsPath = __DIR__;
|
||||
$filePath = $commandsPath . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O comando '{$name}' já existe.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class {$name} extends Command
|
||||
{
|
||||
protected static \$defaultName = '{$commandName}';
|
||||
protected static \$defaultDescription = 'Descrição do comando {$commandName}';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
// Configure argumentos e opções aqui
|
||||
}
|
||||
|
||||
protected function execute(InputInterface \$input, OutputInterface \$output): int
|
||||
{
|
||||
// Sua lógica aqui
|
||||
\$output->writeln('<info>Executando comando {$commandName}...</info>');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Comando '{$name}' criado com sucesso em app/Console/Commands/</info>");
|
||||
$output->writeln("<comment>Lembre-se de registrar o comando no syscli se necessário.</comment>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do comando.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeControllerCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:controller';
|
||||
protected static $defaultDescription = 'Cria um novo controlador em um módulo específico';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('module', InputArgument::REQUIRED, 'O nome do módulo (ex: blog)')
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome do controlador (ex: PostController)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$module = strtolower($input->getArgument('module'));
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
// Garantir que termina com Controller
|
||||
if (!str_ends_with($name, 'Controller')) {
|
||||
$name .= 'Controller';
|
||||
}
|
||||
|
||||
$modulePath = dirname(__DIR__, 3) . '/modules/' . $module;
|
||||
|
||||
if (!is_dir($modulePath)) {
|
||||
$output->writeln("<error>O módulo '{$module}' não existe.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$controllersPath = $modulePath . '/classes/Controllers';
|
||||
if (!is_dir($controllersPath)) {
|
||||
mkdir($controllersPath, 0755, true);
|
||||
}
|
||||
|
||||
$filePath = $controllersPath . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O controlador '{$name}' já existe no módulo '{$module}'.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$namespace = "Modules\\" . ucfirst($module) . "\\Controllers";
|
||||
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
namespace {$namespace};
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Kernel\View;
|
||||
|
||||
/**
|
||||
* Controller {$name}
|
||||
*/
|
||||
class {$name} extends BaseController
|
||||
{
|
||||
/**
|
||||
* Default action
|
||||
*
|
||||
* @param Request \$request
|
||||
* @param Response \$response
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request \$request, Response \$response): Response
|
||||
{
|
||||
// Sua lógica aqui
|
||||
return \$response;
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Controlador '{$name}' criado com sucesso em modules/{$module}/classes/Controllers/</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do controlador.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeExceptionCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:exception';
|
||||
protected static $defaultDescription = 'Cria uma nova classe de exceção';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome da classe de exceção (ex: InvalidPaymentException)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
if (!str_ends_with($name, 'Exception')) {
|
||||
$name .= 'Exception';
|
||||
}
|
||||
|
||||
$directory = dirname(__DIR__, 2) . '/Exceptions';
|
||||
$filePath = $directory . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>A exceção '{$name}' já existe!</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$year = date('Y');
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) {$year} Marco Costa
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class {$name} extends Exception
|
||||
{
|
||||
/**
|
||||
* Exception logic here.
|
||||
*/
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Exceção '{$name}' criada com sucesso em app/Exceptions/</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo da exceção.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+72
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeHelperCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:helper';
|
||||
protected static $defaultDescription = 'Cria um novo arquivo de helper';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome do arquivo helper (ex: string_helpers)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
if (!str_ends_with($name, '.php')) {
|
||||
$name .= '.php';
|
||||
}
|
||||
|
||||
$directory = dirname(__DIR__, 2) . '/Helpers';
|
||||
$filePath = $directory . '/' . $name;
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O helper '{$name}' já existe!</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$year = date('Y');
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) {$year} Marco Costa
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
if (!function_exists('your_function_name')) {
|
||||
/**
|
||||
* Helper description.
|
||||
*/
|
||||
function your_function_name()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Helper '{$name}' criado com sucesso em app/Helpers/</info>");
|
||||
$output->writeln("<comment>Lembre-se de incluir o arquivo no composer.json ou carregar manualmente.</comment>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do helper.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeInterfaceCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:interface';
|
||||
protected static $defaultDescription = 'Cria uma nova interface PHP';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome da interface (ex: PaymentInterface)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
if (!str_ends_with($name, 'Interface')) {
|
||||
$name .= 'Interface';
|
||||
}
|
||||
|
||||
$directory = dirname(__DIR__, 2) . '/Interfaces';
|
||||
$filePath = $directory . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>A interface '{$name}' já existe!</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$year = date('Y');
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) {$year} Marco Costa
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
namespace App\Interfaces;
|
||||
|
||||
interface {$name}
|
||||
{
|
||||
/**
|
||||
* Define interface methods.
|
||||
*/
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Interface '{$name}' criada com sucesso em app/Interfaces/</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo da interface.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeMiddlewareCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:middleware';
|
||||
protected static $defaultDescription = 'Cria um novo middleware na aplicação';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome da classe do middleware (ex: CheckAgeMiddleware)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
// Garante que o nome termine com Middleware para padronização
|
||||
if (!str_ends_with($name, 'Middleware')) {
|
||||
$name .= 'Middleware';
|
||||
}
|
||||
|
||||
$directory = dirname(__DIR__, 2) . '/Middlewares';
|
||||
$filePath = $directory . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O middleware '{$name}' já existe!</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$template = $this->getTemplate($name);
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Middleware '{$name}' criado com sucesso em app/Middlewares/</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do middleware.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getTemplate(string $className): string
|
||||
{
|
||||
$year = date('Y');
|
||||
return <<<PHP
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) {$year} Marco Costa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Marco Costa
|
||||
* Email: contato@syspanel.com.br
|
||||
* Project: SysCMS
|
||||
*/
|
||||
|
||||
namespace App\Middlewares;
|
||||
|
||||
use Closure;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class {$className}
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request \$request
|
||||
* @param Closure \$next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request \$request, Closure \$next)
|
||||
{
|
||||
// Lógica do middleware aqui
|
||||
|
||||
return \$next(\$request);
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeMigrationCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:migration';
|
||||
protected static $defaultDescription = 'Creates a new migration file';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'The migration name (e.g. create_users_table)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
// Convert name to class format (CreateUsersTable)
|
||||
$className = str_replace(' ', '', ucwords(str_replace('_', ' ', $name)));
|
||||
|
||||
// Generate timestamp for ordering
|
||||
$timestamp = date('YmdHis');
|
||||
|
||||
// Define file name
|
||||
$fileName = "{$timestamp}_{$name}.php";
|
||||
|
||||
// Migrations directory path
|
||||
$migrationsPath = dirname(__DIR__, 3) . '/database/migrations';
|
||||
|
||||
if (!is_dir($migrationsPath)) {
|
||||
mkdir($migrationsPath, 0755, true);
|
||||
}
|
||||
|
||||
$filePath = $migrationsPath . '/' . $fileName;
|
||||
|
||||
// Migration template
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class {$className}
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (!Capsule::schema()->hasTable('table_name')) {
|
||||
Capsule::schema()->create('table_name', function (Blueprint \$table) {
|
||||
\$table->id();
|
||||
\$table->timestamps();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Capsule::schema()->dropIfExists('table_name');
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Migração criada com sucesso:</info> {$fileName}");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo de migração.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class MakeMigrationModuleCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:migration-module';
|
||||
protected static $defaultDescription = 'Cria uma nova migração dentro de um módulo específico';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('module', InputArgument::REQUIRED, 'O nome do módulo')
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome da migração (ex: create_posts_table)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$module = strtolower($input->getArgument('module'));
|
||||
$name = Str::snake($input->getArgument('name'));
|
||||
|
||||
$modulePath = dirname(__DIR__, 3) . "/modules/{$module}";
|
||||
|
||||
if (!is_dir($modulePath)) {
|
||||
$output->writeln("<error>Módulo '{$module}' não encontrado.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$migrationsPath = "{$modulePath}/database/migrations";
|
||||
|
||||
if (!is_dir($migrationsPath)) {
|
||||
mkdir($migrationsPath, 0755, true);
|
||||
}
|
||||
|
||||
// Busca o próximo número sequencial para o prefixo (SysCMS usa 001, 002...)
|
||||
$existingFiles = glob("{$migrationsPath}/*.php");
|
||||
$nextNumber = str_pad(count($existingFiles) + 1, 3, '0', STR_PAD_LEFT);
|
||||
|
||||
$fileName = "{$nextNumber}_{$name}.php";
|
||||
$filePath = "{$migrationsPath}/{$fileName}";
|
||||
$className = Str::studly($name);
|
||||
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class {$className}
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Capsule::schema()->create('table_name', function (Blueprint \$table) {
|
||||
\$table->bigIncrements('id');
|
||||
// \$table->string('name');
|
||||
\$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Capsule::schema()->dropIfExists('table_name');
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Migração criada com sucesso: modules/{$module}/database/migrations/{$fileName}</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$output->writeln("<error>Falha ao criar o arquivo de migração.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeModelCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:model';
|
||||
protected static $defaultDescription = 'Cria um novo modelo Eloquent em um módulo específico';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('module', InputArgument::REQUIRED, 'O nome do módulo (ex: blog)')
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome do modelo (ex: Post)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$module = strtolower($input->getArgument('module'));
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
$modulePath = dirname(__DIR__, 3) . '/modules/' . $module;
|
||||
|
||||
if (!is_dir($modulePath)) {
|
||||
$output->writeln("<error>O módulo '{$module}' não existe.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$modelsPath = $modulePath . '/classes/Models';
|
||||
if (!is_dir($modelsPath)) {
|
||||
mkdir($modelsPath, 0755, true);
|
||||
}
|
||||
|
||||
$filePath = $modelsPath . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O modelo '{$name}' já existe no módulo '{$module}'.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$namespace = "Modules\\" . ucfirst($module) . "\\Models";
|
||||
$tableName = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $name)) . 's';
|
||||
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
namespace {$namespace};
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Model {$name}
|
||||
*/
|
||||
class {$name} extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected \$table = '{$tableName}';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected \$fillable = [
|
||||
// Adicione os campos aqui
|
||||
];
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public \$timestamps = true;
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Modelo '{$name}' criado com sucesso em modules/{$module}/classes/Models/</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do modelo.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+129
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeModuleCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:module';
|
||||
protected static $defaultDescription = 'Cria a estrutura básica de um novo módulo';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome do módulo (ex: blog)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = strtolower($input->getArgument('name'));
|
||||
$modulePath = dirname(__DIR__, 3) . '/modules/' . $name;
|
||||
|
||||
if (is_dir($modulePath)) {
|
||||
$output->writeln("<error>O módulo '{$name}' já existe.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
// Criar estrutura de diretórios
|
||||
$directories = [
|
||||
$modulePath,
|
||||
$modulePath . '/routes',
|
||||
$modulePath . '/views',
|
||||
$modulePath . '/classes',
|
||||
$modulePath . '/classes/Controllers',
|
||||
$modulePath . '/classes/Models',
|
||||
];
|
||||
|
||||
foreach ($directories as $dir) {
|
||||
if (!mkdir($dir, 0755, true)) {
|
||||
$output->writeln("<error>Falha ao criar diretório: {$dir}</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Criar module.json
|
||||
$moduleJson = [
|
||||
'name' => ucfirst($name),
|
||||
'version' => '1.0.0',
|
||||
'description' => 'Descrição do módulo ' . ucfirst($name),
|
||||
'author' => 'SysCMS',
|
||||
'enabled' => true
|
||||
];
|
||||
file_put_contents($modulePath . '/module.json', json_encode($moduleJson, JSON_PRETTY_PRINT));
|
||||
|
||||
// Criar rotas web.php
|
||||
$webRoutes = <<<PHP
|
||||
<?php
|
||||
|
||||
/** @var \Slim\App \$app */
|
||||
|
||||
\$app->group('/{$name}', function (\$group) {
|
||||
\$group->get('', [\Modules\\ucfirst($name)\Controllers\\ucfirst($name)Controller::class, 'index']);
|
||||
});
|
||||
PHP;
|
||||
file_put_contents($modulePath . '/routes/web.php', $webRoutes);
|
||||
|
||||
// Criar rotas api.php
|
||||
$apiRoutes = "<?php\n\n/** @var \Slim\App \$app */\n";
|
||||
file_put_contents($modulePath . '/routes/api.php', $apiRoutes);
|
||||
|
||||
// Criar Controlador inicial
|
||||
$controllerName = ucfirst($name) . 'Controller';
|
||||
$namespace = "Modules\\" . ucfirst($name) . "\\Controllers";
|
||||
$controllerTemplate = <<<PHP
|
||||
<?php
|
||||
|
||||
namespace {$namespace};
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Kernel\View;
|
||||
|
||||
/**
|
||||
* Controller for {$name} module
|
||||
*/
|
||||
class {$controllerName} extends BaseController
|
||||
{
|
||||
/**
|
||||
* Index action
|
||||
*
|
||||
* @param Request \$request
|
||||
* @param Response \$response
|
||||
* @return Response
|
||||
*/
|
||||
public function index(Request \$request, Response \$response): Response
|
||||
{
|
||||
return View::render(\$response, '@{$name}/index.twig', [
|
||||
'title' => 'Módulo ' . ucfirst('{$name}')
|
||||
]);
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
file_put_contents($modulePath . '/classes/Controllers/' . $controllerName . '.php', $controllerTemplate);
|
||||
|
||||
// Criar view inicial
|
||||
$viewTemplate = <<<HTML
|
||||
{% extends "layouts/dashboard.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<h1 class="mt-4">{{ title }}</h1>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
Este é o módulo {{ title }} gerado automaticamente.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
HTML;
|
||||
file_put_contents($modulePath . '/views/index.twig', $viewTemplate);
|
||||
|
||||
$output->writeln("<info>Módulo '{$name}' criado com sucesso em modules/{$name}</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeRepositoryCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:repository';
|
||||
protected static $defaultDescription = 'Cria uma nova classe de repositório';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome da classe de repositório (ex: UserRepository)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
if (!str_ends_with($name, 'Repository')) {
|
||||
$name .= 'Repository';
|
||||
}
|
||||
|
||||
$directory = dirname(__DIR__, 2) . '/Repositories';
|
||||
$filePath = $directory . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O repositório '{$name}' já existe!</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$year = date('Y');
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) {$year} Marco Costa
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
class {$name}
|
||||
{
|
||||
/**
|
||||
* Repository logic here.
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
// Return all records
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Repositório '{$name}' criado com sucesso em app/Repositories/</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do repositório.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeSeedCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:seed';
|
||||
protected static $defaultDescription = 'Cria uma nova classe de seeder';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome da classe seeder (ex: UserSeeder)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
// Garantir que termina com Seeder
|
||||
if (!str_ends_with($name, 'Seeder')) {
|
||||
$name .= 'Seeder';
|
||||
}
|
||||
|
||||
$seedersPath = dirname(__DIR__, 3) . '/database/seeders';
|
||||
|
||||
if (!is_dir($seedersPath)) {
|
||||
mkdir($seedersPath, 0755, true);
|
||||
}
|
||||
|
||||
$filePath = $seedersPath . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O seeder '{$name}' já existe.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class {$name}
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// Capsule::table('users')->insert([
|
||||
// 'user_name' => 'Admin',
|
||||
// 'user_email' => 'admin@example.com',
|
||||
// 'user_password' => password_hash('password', PASSWORD_DEFAULT),
|
||||
// ]);
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Seeder criado com sucesso:</info> database/seeders/{$name}.php");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do seeder.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeServiceCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:service';
|
||||
protected static $defaultDescription = 'Cria uma nova classe de serviço';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome da classe de serviço (ex: PaymentService)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
if (!str_ends_with($name, 'Service')) {
|
||||
$name .= 'Service';
|
||||
}
|
||||
|
||||
$directory = dirname(__DIR__, 2) . '/Services';
|
||||
$filePath = $directory . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O serviço '{$name}' já existe!</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$year = date('Y');
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) {$year} Marco Costa
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class {$name}
|
||||
{
|
||||
/**
|
||||
* Service logic here.
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
// Implement logic
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Serviço '{$name}' criado com sucesso em app/Services/</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do serviço.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class MakeTraitCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:trait';
|
||||
protected static $defaultDescription = 'Cria uma nova Trait PHP';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome da trait (ex: HasUuid)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
$directory = dirname(__DIR__, 2) . '/Traits';
|
||||
$filePath = $directory . '/' . $name . '.php';
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>A trait '{$name}' já existe!</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$year = date('Y');
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) {$year} Marco Costa
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
namespace App\Traits;
|
||||
|
||||
trait {$name}
|
||||
{
|
||||
/**
|
||||
* Trait logic here.
|
||||
*/
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Trait '{$name}' criada com sucesso em app/Traits/</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo da trait.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class MakeViewCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'make:view';
|
||||
protected static $defaultDescription = 'Cria um novo template Twig';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome do template (ex: users/index)')
|
||||
->addOption('module', 'm', InputOption::VALUE_OPTIONAL, 'O módulo onde o template será criado');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$name = $input->getArgument('name');
|
||||
$module = $input->getOption('module');
|
||||
|
||||
// Garante a extensão .twig
|
||||
if (!str_ends_with($name, '.twig')) {
|
||||
$name .= '.twig';
|
||||
}
|
||||
|
||||
if ($module) {
|
||||
$directory = dirname(__DIR__, 3) . "/modules/{$module}/views";
|
||||
} else {
|
||||
$directory = dirname(__DIR__, 3) . "/templates";
|
||||
}
|
||||
|
||||
$filePath = $directory . '/' . $name;
|
||||
$fileDir = dirname($filePath);
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O template '{$name}' já existe!</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!is_dir($fileDir)) {
|
||||
mkdir($fileDir, 0755, true);
|
||||
}
|
||||
|
||||
$template = "{% extends \"layouts/base.twig\" %}\n\n{% block content %}\n<div class=\"container mt-4\">\n <h1>" . ucfirst(basename($name, '.twig')) . "</h1>\n <p>Novo template criado via CLI.</p>\n</div>\n{% endblock %}\n";
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Template '{$name}' criado com sucesso em " . ($module ? "modules/{$module}/views/" : "templates/") . "</info>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do template.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+144
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class MigrateCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'migrate';
|
||||
protected static $defaultDescription = 'Executes database migrations';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp('This command checks and executes all pending database migrations.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln([
|
||||
'Iniciando execução das migrations...',
|
||||
'=====================================',
|
||||
'',
|
||||
]);
|
||||
|
||||
// Ensure migrations table exists
|
||||
$this->ensureMigrationsTableExists();
|
||||
|
||||
$migrationsPath = dirname(__DIR__, 3) . '/database/migrations';
|
||||
$modulesPath = dirname(__DIR__, 3) . '/modules';
|
||||
|
||||
$migrationFiles = [];
|
||||
|
||||
// Core migrations
|
||||
if (is_dir($migrationsPath)) {
|
||||
$coreFiles = glob($migrationsPath . '/*.php');
|
||||
if ($coreFiles) {
|
||||
$migrationFiles = array_merge($migrationFiles, $coreFiles);
|
||||
}
|
||||
} else {
|
||||
$output->writeln("<error>Diretório de migrations não encontrado: $migrationsPath</error>");
|
||||
}
|
||||
|
||||
// Module migrations
|
||||
if (is_dir($modulesPath)) {
|
||||
$moduleFiles = glob($modulesPath . '/*/database/migrations/*.php');
|
||||
if ($moduleFiles) {
|
||||
$migrationFiles = array_merge($migrationFiles, $moduleFiles);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort migration files by filename (keeping chronological order if timestamp/numbering exists)
|
||||
usort($migrationFiles, function($a, $b) {
|
||||
return basename($a) <=> basename($b);
|
||||
});
|
||||
|
||||
if (empty($migrationFiles)) {
|
||||
$output->writeln('<info>Nenhuma migração encontrada.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
// Get already executed migrations
|
||||
$executedMigrations = Capsule::table('migrations')->pluck('migration')->toArray();
|
||||
$nextBatch = Capsule::table('migrations')->max('batch') + 1;
|
||||
$count = 0;
|
||||
|
||||
foreach ($migrationFiles as $file) {
|
||||
$fileName = basename($file, '.php');
|
||||
|
||||
// Skip if already executed
|
||||
if (in_array($fileName, $executedMigrations)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove numeric prefix (e.g. 001_)
|
||||
$cleanName = preg_replace('/^\d+_/', '', $fileName);
|
||||
|
||||
// Convert snake_case to PascalCase (e.g. create_bus_table -> CreateBusTable)
|
||||
$className = str_replace(' ', '', ucwords(str_replace('_', ' ', $cleanName)));
|
||||
|
||||
$output->write("Executando migration: <info>{$fileName}</info>... ");
|
||||
|
||||
try {
|
||||
require_once $file;
|
||||
|
||||
if (class_exists($className)) {
|
||||
$migration = new $className();
|
||||
|
||||
// Check if up method exists
|
||||
if (method_exists($migration, 'up')) {
|
||||
$migration->up();
|
||||
|
||||
// Record migration as executed
|
||||
Capsule::table('migrations')->insert([
|
||||
'migration' => $fileName,
|
||||
'batch' => $nextBatch
|
||||
]);
|
||||
|
||||
$output->writeln('<info>OK</info>');
|
||||
$count++;
|
||||
} else {
|
||||
$output->writeln('<comment>SKIPPED (método up não encontrado)</comment>');
|
||||
}
|
||||
} else {
|
||||
$output->writeln("<error>ERRO (Classe {$className} não encontrada)</error>");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>FALHA</error>");
|
||||
$output->writeln("<error>Erro: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if ($count === 0) {
|
||||
$output->writeln('<info>Nada para migrar.</info>');
|
||||
} else {
|
||||
$output->writeln([
|
||||
'',
|
||||
"<info>Total de {$count} migration(s) processada(s) com sucesso!</info>",
|
||||
]);
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the migrations table exists in the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function ensureMigrationsTableExists(): void
|
||||
{
|
||||
if (!Capsule::schema()->hasTable('migrations')) {
|
||||
Capsule::schema()->create('migrations', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->string('migration');
|
||||
$table->integer('batch');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
|
||||
class MigrateFreshCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'migrate:fresh';
|
||||
protected static $defaultDescription = 'Drop all tables and re-run all migrations';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('seed', null, InputOption::VALUE_NONE, 'Indicates if the seed command should be re-run');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$output->writeln('<info>Iniciando limpeza do banco de dados (fresh)...</info>');
|
||||
|
||||
// 1. Wipe database
|
||||
$wipeCommand = $this->getApplication()->find('db:wipe');
|
||||
$wipeInput = new ArrayInput(['--force' => true]);
|
||||
$wipeCommand->run($wipeInput, $output);
|
||||
|
||||
// 2. Run migrations
|
||||
$migrateCommand = $this->getApplication()->find('migrate');
|
||||
$migrateInput = new ArrayInput([]);
|
||||
$migrateCommand->run($migrateInput, $output);
|
||||
|
||||
// 3. Optional seed
|
||||
if ($input->getOption('seed')) {
|
||||
$seedCommand = $this->getApplication()->find('db:seed');
|
||||
$seedInput = new ArrayInput([]);
|
||||
$seedCommand->run($seedInput, $output);
|
||||
}
|
||||
|
||||
$output->writeln('<info>Operação migrate:fresh concluída com sucesso!</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
|
||||
class MigrateRefreshCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'migrate:refresh';
|
||||
protected static $defaultDescription = 'Reset and re-run all migrations';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('step', 's', InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted', 0)
|
||||
->addOption('seed', null, InputOption::VALUE_NONE, 'Indicates if the seed command should be re-run');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$step = (int) $input->getOption('step');
|
||||
|
||||
if ($step > 0) {
|
||||
$output->writeln("<info>Revertendo {$step} passos de migração...</info>");
|
||||
$rollbackCommand = $this->getApplication()->find('migrate:rollback');
|
||||
$rollbackInput = new ArrayInput(['--step' => $step]);
|
||||
$rollbackCommand->run($rollbackInput, $output);
|
||||
} else {
|
||||
$output->writeln('<info>Revertendo todas as migrações (reset)...</info>');
|
||||
// Reset all by calling rollback in loop or a specific reset command
|
||||
// Assuming we'll use rollback in loop for simplicity or adding a reset later
|
||||
// Here we use step=999 as a convention for "all" in our rollback implementation
|
||||
$rollbackCommand = $this->getApplication()->find('migrate:rollback');
|
||||
$rollbackInput = new ArrayInput(['--step' => 999]);
|
||||
$rollbackCommand->run($rollbackInput, $output);
|
||||
}
|
||||
|
||||
$output->writeln('<info>Executando migrações novamente...</info>');
|
||||
$migrateCommand = $this->getApplication()->find('migrate');
|
||||
$migrateInput = new ArrayInput([]);
|
||||
$migrateCommand->run($migrateInput, $output);
|
||||
|
||||
if ($input->getOption('seed')) {
|
||||
$output->writeln('<info>Executando seeders...</info>');
|
||||
$seedCommand = $this->getApplication()->find('db:seed');
|
||||
$seedInput = new ArrayInput([]);
|
||||
$seedCommand->run($seedInput, $output);
|
||||
}
|
||||
|
||||
$output->writeln('<info>Operação migrate:refresh concluída com sucesso!</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class MigrationStatusCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'migrate:status';
|
||||
protected static $defaultDescription = 'Mostra o status de todas as migrações';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (!Capsule::schema()->hasTable('migrations')) {
|
||||
$output->writeln('<error>Tabela de migrations não encontrada.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$migrationsPath = dirname(__DIR__, 3) . '/database/migrations';
|
||||
$modulesPath = dirname(__DIR__, 3) . '/modules';
|
||||
|
||||
$migrationFiles = [];
|
||||
|
||||
// Core migrations
|
||||
if (is_dir($migrationsPath)) {
|
||||
$coreFiles = glob($migrationsPath . '/*.php');
|
||||
if ($coreFiles) {
|
||||
$migrationFiles = array_merge($migrationFiles, $coreFiles);
|
||||
}
|
||||
}
|
||||
|
||||
// Module migrations
|
||||
if (is_dir($modulesPath)) {
|
||||
$moduleFiles = glob($modulesPath . '/*/database/migrations/*.php');
|
||||
if ($moduleFiles) {
|
||||
$migrationFiles = array_merge($migrationFiles, $moduleFiles);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort migration files
|
||||
usort($migrationFiles, function($a, $b) {
|
||||
return basename($a) <=> basename($b);
|
||||
});
|
||||
|
||||
// Get executed migrations
|
||||
$executedMigrations = Capsule::table('migrations')->get()->keyBy('migration');
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Executada?', 'Migration', 'Batch']);
|
||||
|
||||
foreach ($migrationFiles as $file) {
|
||||
$fileName = basename($file, '.php');
|
||||
$executed = $executedMigrations->has($fileName);
|
||||
|
||||
$table->addRow([
|
||||
$executed ? '<info>Sim</info>' : '<comment>Não</comment>',
|
||||
$fileName,
|
||||
$executed ? $executedMigrations->get($fileName)->batch : '-'
|
||||
]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+87
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class ModuleDeleteCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'module:delete';
|
||||
protected static $defaultDescription = 'Remove fisicamente um módulo e suas tabelas associadas';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('module', InputArgument::REQUIRED, 'O nome do módulo a ser removido')
|
||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Confirmar a remoção sem prompt');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$moduleName = $input->getArgument('module');
|
||||
$force = $input->getOption('force');
|
||||
$modulePath = dirname(__DIR__, 3) . '/modules/' . $moduleName;
|
||||
|
||||
if (!is_dir($modulePath)) {
|
||||
$output->writeln("<error>Módulo '{$moduleName}' não encontrado em modules/.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!$force) {
|
||||
$output->writeln("<comment>Você tem certeza que deseja remover o módulo '{$moduleName}' e TODAS as suas tabelas associadas?</comment>");
|
||||
$output->writeln("<info>Use a opção --force para confirmar.</info>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
// 1. Drop associated tables if listed in module.json
|
||||
$jsonPath = $modulePath . '/module.json';
|
||||
if (file_exists($jsonPath)) {
|
||||
$config = json_decode(file_get_contents($jsonPath), true);
|
||||
if (isset($config['tables']) && is_array($config['tables'])) {
|
||||
$output->writeln("<info>Limpando tabelas do banco de dados...</info>");
|
||||
Capsule::connection()->statement('SET FOREIGN_KEY_CHECKS = 0');
|
||||
foreach ($config['tables'] as $table) {
|
||||
$output->write("Dropando tabela: <comment>{$table}</comment>... ");
|
||||
Capsule::schema()->dropIfExists($table);
|
||||
$output->writeln('<info>OK</info>');
|
||||
}
|
||||
Capsule::connection()->statement('SET FOREIGN_KEY_CHECKS = 1');
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Remove files
|
||||
$output->writeln("<info>Removendo arquivos do módulo...</info>");
|
||||
$this->deleteDirectory($modulePath);
|
||||
|
||||
$output->writeln("<info>Módulo '{$moduleName}' removido com sucesso!</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function deleteDirectory($dir): bool
|
||||
{
|
||||
if (!file_exists($dir)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_dir($dir)) {
|
||||
return unlink($dir);
|
||||
}
|
||||
|
||||
foreach (scandir($dir) as $item) {
|
||||
if ($item == '.' || $item == '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return rmdir($dir);
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ModuleDisableCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'module:disable';
|
||||
protected static $defaultDescription = 'Desativa um módulo no arquivo module.json';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('module', InputArgument::REQUIRED, 'O nome do módulo a ser desativado');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$moduleName = $input->getArgument('module');
|
||||
$modulePath = dirname(__DIR__, 3) . '/modules/' . $moduleName . '/module.json';
|
||||
|
||||
if (!file_exists($modulePath)) {
|
||||
$output->writeln("<error>Módulo '{$moduleName}' não encontrado ou arquivo module.json inexistente.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$config = json_decode(file_get_contents($modulePath), true);
|
||||
|
||||
if ($config === null) {
|
||||
$output->writeln("<error>Erro ao ler o arquivo module.json do módulo '{$moduleName}'.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$isActive = $config['module_active'] ?? $config['module_ative'] ?? false;
|
||||
if ($isActive === false) {
|
||||
$output->writeln("<comment>O módulo '{$moduleName}' já está desativado.</comment>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
// Maintain the key already used in the file if possible
|
||||
if (isset($config['module_ative'])) {
|
||||
$config['module_ative'] = false;
|
||||
} else {
|
||||
$config['module_active'] = false;
|
||||
}
|
||||
|
||||
if (file_put_contents($modulePath, json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES))) {
|
||||
$output->writeln("<info>Módulo '{$moduleName}' desativado com sucesso!</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$output->writeln("<error>Falha ao atualizar o arquivo module.json do módulo '{$moduleName}'.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ModuleEnableCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'module:enable';
|
||||
protected static $defaultDescription = 'Ativa um módulo no arquivo module.json';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('module', InputArgument::REQUIRED, 'O nome do módulo a ser ativado');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$moduleName = $input->getArgument('module');
|
||||
$modulePath = dirname(__DIR__, 3) . '/modules/' . $moduleName . '/module.json';
|
||||
|
||||
if (!file_exists($modulePath)) {
|
||||
$output->writeln("<error>Módulo '{$moduleName}' não encontrado ou arquivo module.json inexistente.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$config = json_decode(file_get_contents($modulePath), true);
|
||||
|
||||
if ($config === null) {
|
||||
$output->writeln("<error>Erro ao ler o arquivo module.json do módulo '{$moduleName}'.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$isActive = $config['module_active'] ?? $config['module_ative'] ?? false;
|
||||
if ($isActive === true) {
|
||||
$output->writeln("<comment>O módulo '{$moduleName}' já está ativado.</comment>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
// Maintain the key already used in the file if possible
|
||||
if (isset($config['module_ative'])) {
|
||||
$config['module_ative'] = true;
|
||||
} else {
|
||||
$config['module_active'] = true;
|
||||
}
|
||||
|
||||
if (file_put_contents($modulePath, json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES))) {
|
||||
$output->writeln("<info>Módulo '{$moduleName}' ativado com sucesso!</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$output->writeln("<error>Falha ao atualizar o arquivo module.json do módulo '{$moduleName}'.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use Kernel\ModuleLoader;
|
||||
|
||||
class ModuleListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'module:list';
|
||||
protected static $defaultDescription = 'Lista todos os módulos instalados e suas informações';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$modulesPath = dirname(__DIR__, 3) . '/modules';
|
||||
$loader = new ModuleLoader($modulesPath);
|
||||
|
||||
try {
|
||||
// Get all directories in modules/
|
||||
$dirs = glob($modulesPath . '/*', GLOB_ONLYDIR);
|
||||
|
||||
if (empty($dirs)) {
|
||||
$output->writeln('<info>Nenhum módulo encontrado em modules/.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$output->writeln('<info>Módulos do Sistema:</info>');
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Nome', 'Versão', 'Ativo', 'Pronto', 'DB', 'Descrição']);
|
||||
|
||||
// Get registered modules from DB using correct column name
|
||||
$dbModules = [];
|
||||
if (Capsule::schema()->hasTable('modules')) {
|
||||
$dbModules = Capsule::table('modules')->pluck('modules_name')->toArray();
|
||||
}
|
||||
|
||||
foreach ($dirs as $dir) {
|
||||
$name = basename($dir);
|
||||
$jsonFile = $dir . '/module.json';
|
||||
|
||||
$version = 'N/A';
|
||||
$active = '<comment>Não</comment>';
|
||||
$ready = '<comment>Não</comment>';
|
||||
$dbStatus = in_array($name, $dbModules) ? '<info>Sim</info>' : '<comment>Não</comment>';
|
||||
$description = 'Sem descrição';
|
||||
|
||||
if (file_exists($jsonFile)) {
|
||||
$config = json_decode(file_get_contents($jsonFile), true);
|
||||
if ($config) {
|
||||
$version = $config['version'] ?? '1.0.0';
|
||||
// Check both module_active and module_ative, default to true if missing
|
||||
$isActive = $config['module_active'] ?? $config['module_ative'] ?? true;
|
||||
$active = $isActive ? '<info>Sim</info>' : '<comment>Não</comment>';
|
||||
$isReady = $config['ready'] ?? true;
|
||||
$ready = $isReady ? '<info>Sim</info>' : '<comment>Não</comment>';
|
||||
$description = $config['description'] ?? 'Sem descrição';
|
||||
}
|
||||
}
|
||||
|
||||
$table->addRow([
|
||||
$name,
|
||||
$version,
|
||||
$active,
|
||||
$ready,
|
||||
$dbStatus,
|
||||
substr($description, 0, 40) . (strlen($description) > 40 ? '...' : '')
|
||||
]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
$output->writeln("<info>Total de módulos: " . count($dirs) . "</info>");
|
||||
|
||||
return Command::SUCCESS;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln('<error>Erro ao listar módulos: ' . $e->getMessage() . '</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ModuleMakeProviderCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'module:make-provider';
|
||||
protected static $defaultDescription = 'Cria um novo Service Provider para um módulo específico';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('module', InputArgument::REQUIRED, 'O nome do módulo')
|
||||
->addArgument('name', InputArgument::REQUIRED, 'O nome do Service Provider (ex: EventServiceProvider)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$moduleName = $input->getArgument('module');
|
||||
$name = $input->getArgument('name');
|
||||
|
||||
if (!str_ends_with($name, 'ServiceProvider')) {
|
||||
$name .= 'ServiceProvider';
|
||||
}
|
||||
|
||||
$modulePath = dirname(__DIR__, 3) . '/modules/' . $moduleName;
|
||||
$directory = $modulePath . '/Providers';
|
||||
$filePath = $directory . '/' . $name . '.php';
|
||||
|
||||
if (!is_dir($modulePath)) {
|
||||
$output->writeln("<error>Módulo '{$moduleName}' não encontrado.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
$output->writeln("<error>O Service Provider '{$name}' já existe!</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0755, true);
|
||||
}
|
||||
|
||||
$year = date('Y');
|
||||
$moduleNamespace = "Modules\\" . ucfirst($moduleName);
|
||||
$template = <<<PHP
|
||||
<?php
|
||||
|
||||
/**
|
||||
* SysCMS - Content Management System
|
||||
*
|
||||
* Copyright (c) {$year} Marco Costa
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
namespace {$moduleNamespace}\Providers;
|
||||
|
||||
class {$name}
|
||||
{
|
||||
/**
|
||||
* Register the service provider.
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
// Register services in the container
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot the service provider.
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
// Boot logic
|
||||
}
|
||||
}
|
||||
PHP;
|
||||
|
||||
if (file_put_contents($filePath, $template)) {
|
||||
$output->writeln("<info>Service Provider '{$name}' criado com sucesso em modules/{$moduleName}/Providers/</info>");
|
||||
$output->writeln("<comment>Lembre-se de registrar o provider no arquivo module.json se necessário.</comment>");
|
||||
return Command::SUCCESS;
|
||||
} else {
|
||||
$output->writeln("<error>Falha ao criar o arquivo do Service Provider.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ModulePublishCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'module:publish';
|
||||
protected static $defaultDescription = 'Copia os assets de um módulo para a pasta public do sistema';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('module', InputArgument::REQUIRED, 'O nome do módulo');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$module = strtolower($input->getArgument('module'));
|
||||
$modulePath = dirname(__DIR__, 3) . "/modules/{$module}";
|
||||
|
||||
if (!is_dir($modulePath)) {
|
||||
$output->writeln("<error>Módulo '{$module}' não encontrado.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$assetsPath = "{$modulePath}/assets";
|
||||
if (!is_dir($assetsPath)) {
|
||||
$output->writeln("<comment>Nenhum diretório 'assets' encontrado no módulo '{$module}'.</comment>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$publicPath = dirname(__DIR__, 3) . "/public/assets/modules/{$module}";
|
||||
|
||||
if (!is_dir($publicPath)) {
|
||||
mkdir($publicPath, 0755, true);
|
||||
}
|
||||
|
||||
$output->writeln("<info>Copiando assets de '{$module}' para 'public/assets/modules/{$module}'...</info>");
|
||||
|
||||
$this->copyDirectory($assetsPath, $publicPath);
|
||||
|
||||
$output->writeln("<info>Assets publicados com sucesso!</info>");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function copyDirectory($source, $destination)
|
||||
{
|
||||
$dir = opendir($source);
|
||||
@mkdir($destination);
|
||||
while (false !== ($file = readdir($dir))) {
|
||||
if (($file != '.') && ($file != '..')) {
|
||||
if (is_dir($source . '/' . $file)) {
|
||||
$this->copyDirectory($source . '/' . $file, $destination . '/' . $file);
|
||||
} else {
|
||||
copy($source . '/' . $file, $destination . '/' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($dir);
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class ModuleRegisterCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'module:register';
|
||||
protected static $defaultDescription = 'Registra um módulo existente na tabela modules do banco de dados';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('module', InputArgument::REQUIRED, 'O nome do diretório do módulo');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$moduleName = $input->getArgument('module');
|
||||
$modulePath = dirname(__DIR__, 3) . '/modules/' . $moduleName . '/module.json';
|
||||
|
||||
if (!file_exists($modulePath)) {
|
||||
$output->writeln("<error>Módulo '{$moduleName}' não encontrado ou arquivo module.json inexistente.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$config = json_decode(file_get_contents($modulePath), true);
|
||||
|
||||
if ($config === null) {
|
||||
$output->writeln("<error>Erro ao processar o arquivo module.json do módulo '{$moduleName}'.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
// Verifica se a tabela modules existe
|
||||
if (!Capsule::schema()->hasTable('modules')) {
|
||||
$output->writeln("<error>A tabela 'modules' não existe no banco de dados. Execute as migrations primeiro.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
// Verifica se o módulo já está registrado usando a coluna correta
|
||||
$existing = Capsule::table('modules')->where('modules_name', $moduleName)->first();
|
||||
|
||||
$data = [
|
||||
'modules_name' => $moduleName,
|
||||
'modules_display_name' => $config['display_name'] ?? $moduleName,
|
||||
'modules_description' => $config['description'] ?? '',
|
||||
'modules_version' => $config['version'] ?? '1.0.0',
|
||||
'modules_ative' => $config['module_active'] ?? $config['module_ative'] ?? true,
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
if ($existing) {
|
||||
Capsule::table('modules')->where('modules_name', $moduleName)->update($data);
|
||||
$output->writeln("<info>Registro do módulo '{$moduleName}' atualizado com sucesso!</info>");
|
||||
} else {
|
||||
$data['created_at'] = date('Y-m-d H:i:s');
|
||||
Capsule::table('modules')->insert($data);
|
||||
$output->writeln("<info>Módulo '{$moduleName}' registrado com sucesso na tabela modules!</info>");
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
class ModuleTestCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'module:test';
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription('Executa testes automatizados para um módulo específico')
|
||||
->addArgument('name', InputArgument::REQUIRED, 'Nome do módulo');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$moduleName = strtolower($input->getArgument('name'));
|
||||
$modulePath = dirname(dirname(dirname(__DIR__))) . '/modules/' . $moduleName;
|
||||
|
||||
if (!is_dir($modulePath)) {
|
||||
$io->error("Módulo '{$moduleName}' não encontrado em {$modulePath}");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$testPath = $modulePath . '/tests';
|
||||
if (!is_dir($testPath)) {
|
||||
$io->warning("O módulo '{$moduleName}' não possui uma pasta de testes em {$testPath}.");
|
||||
return Command::INVALID;
|
||||
}
|
||||
|
||||
$io->title("Iniciando testes para o módulo: " . ucfirst($moduleName));
|
||||
|
||||
// Execute PHPUnit pointing to the module's test directory
|
||||
// Using vendor/bin/phpunit which is standard for the project
|
||||
$phpunitExec = dirname(dirname(dirname(__DIR__))) . '/vendor/bin/phpunit';
|
||||
|
||||
// We use the full path to phpunit to avoid command not found issues
|
||||
$command = "php \"{$phpunitExec}\" \"{$testPath}\"";
|
||||
|
||||
$io->note("Executando: {$command}");
|
||||
|
||||
passthru($command, $exitCode);
|
||||
|
||||
if ($exitCode === 0) {
|
||||
$io->success("Todos os testes do módulo '{$moduleName}' passaram!");
|
||||
} else {
|
||||
$io->error("Falha nos testes do módulo '{$moduleName}'.");
|
||||
}
|
||||
|
||||
return $exitCode === 0 ? Command::SUCCESS : Command::FAILURE;
|
||||
}
|
||||
}
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class OpcacheClearCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'opcache:clear';
|
||||
protected static $defaultDescription = 'Limpa o cache do OPcache (PHP)';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setHelp('Este comando executa a função opcache_reset() para invalidar todo o cache de bytecode.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (!function_exists('opcache_reset')) {
|
||||
$output->writeln('<error>OPcache não está habilitado ou a função opcache_reset() não está disponível.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (opcache_reset()) {
|
||||
$output->writeln('<info>OPcache limpo com sucesso!</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$output->writeln('<error>Falha ao limpar o OPcache.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class PermissionListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'permission:list';
|
||||
protected static $defaultDescription = 'Lista todas as permissões cadastradas no sistema';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
if (!Capsule::schema()->hasTable('permissions')) {
|
||||
$output->writeln('<error>Tabela de permissões não encontrada.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$permissions = Capsule::table('permissions')
|
||||
->orderBy('permission_name')
|
||||
->get();
|
||||
|
||||
if ($permissions->isEmpty()) {
|
||||
$output->writeln('<info>Nenhuma permissão encontrada.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['ID', 'Nome', 'Slug', 'Descrição']);
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
$table->addRow([
|
||||
$permission->permission_id,
|
||||
$permission->permission_name,
|
||||
$permission->permission_slug,
|
||||
$permission->permission_description ?? '-'
|
||||
]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+130
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class RollbackCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'migrate:rollback';
|
||||
protected static $defaultDescription = 'Reverte a última leva de migrações do banco de dados';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp('Este comando reverte as migrações que foram executadas na última operação de migração.')
|
||||
->addOption('step', 's', \Symfony\Component\Console\Input\InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted', 0);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$step = (int) $input->getOption('step');
|
||||
|
||||
$output->writeln([
|
||||
'Iniciando rollback das migrations...',
|
||||
'=====================================',
|
||||
'',
|
||||
]);
|
||||
|
||||
if (!Capsule::schema()->hasTable('migrations')) {
|
||||
$output->writeln('<error>Tabela de migrations não encontrada.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if ($step === 999) {
|
||||
// Special case for migrate:reset or fresh
|
||||
$migrationsToRollback = Capsule::table('migrations')
|
||||
->orderBy('id', 'desc')
|
||||
->get();
|
||||
} elseif ($step > 0) {
|
||||
// Revert specific number of migrations
|
||||
$migrationsToRollback = Capsule::table('migrations')
|
||||
->orderBy('id', 'desc')
|
||||
->limit($step)
|
||||
->get();
|
||||
} else {
|
||||
// Pegar o último batch
|
||||
$lastBatch = Capsule::table('migrations')->max('batch');
|
||||
|
||||
if (!$lastBatch) {
|
||||
$output->writeln('<info>Nenhuma migração para reverter.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$migrationsToRollback = Capsule::table('migrations')
|
||||
->where('batch', $lastBatch)
|
||||
->orderBy('id', 'desc')
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($migrationsToRollback->isEmpty()) {
|
||||
$output->writeln('<info>Nenhuma migração para reverter.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$migrationsPath = dirname(__DIR__, 3) . '/database/migrations';
|
||||
$modulesPath = dirname(__DIR__, 3) . '/modules';
|
||||
|
||||
foreach ($migrationsToRollback as $row) {
|
||||
$fileName = $row->migration;
|
||||
$file = $this->findMigrationFile($fileName, $migrationsPath, $modulesPath);
|
||||
|
||||
if (!$file) {
|
||||
$output->writeln("<error>Arquivo de migração não encontrado: {$fileName}.php</error>");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Converter nome para classe
|
||||
$cleanName = preg_replace('/^\d+_/', '', $fileName);
|
||||
$className = str_replace(' ', '', ucwords(str_replace('_', ' ', $cleanName)));
|
||||
|
||||
$output->write("Revertendo migration: <info>{$fileName}</info>... ");
|
||||
|
||||
try {
|
||||
require_once $file;
|
||||
|
||||
if (class_exists($className)) {
|
||||
$migration = new $className();
|
||||
|
||||
if (method_exists($migration, 'down')) {
|
||||
$migration->down();
|
||||
|
||||
// Remover registro da tabela de migrations
|
||||
Capsule::table('migrations')->where('id', $row->id)->delete();
|
||||
|
||||
$output->writeln('<info>OK</info>');
|
||||
} else {
|
||||
$output->writeln('<comment>Método down() não encontrado.</comment>');
|
||||
}
|
||||
} else {
|
||||
$output->writeln("<error>Classe {$className} não encontrada.</error>");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function findMigrationFile(string $name, string $corePath, string $modulesPath): ?string
|
||||
{
|
||||
// Procurar no core
|
||||
$coreFile = $corePath . '/' . $name . '.php';
|
||||
if (file_exists($coreFile)) {
|
||||
return $coreFile;
|
||||
}
|
||||
|
||||
// Procurar nos módulos
|
||||
$moduleFiles = glob($modulesPath . '/*/database/migrations/' . $name . '.php');
|
||||
if ($moduleFiles && count($moduleFiles) > 0) {
|
||||
return $moduleFiles[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Kernel\Application;
|
||||
use Kernel\ModuleLoader;
|
||||
|
||||
class RouteListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'route:list';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setDescription('Lists all routes registered in the application.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// We need to instantiate the application to load the routes
|
||||
// But be careful not to execute session_start() if it is already active or causes output
|
||||
|
||||
// Simulate application environment
|
||||
if (session_status() == PHP_SESSION_NONE) {
|
||||
// Avoid headers error if something attempts to start session
|
||||
// But Application initSession attempts to start.
|
||||
// Let's suppress session errors for the command
|
||||
@session_start();
|
||||
}
|
||||
|
||||
$app = new Application();
|
||||
|
||||
// The Application constructor already loads routes via initRouter and initModuleLoader
|
||||
// But we must ensure it loads everything that adds routes
|
||||
|
||||
// Since Application is a singleton, we can try to get the instance or create it
|
||||
// If we create new Application(), it runs the constructor.
|
||||
|
||||
$routes = $app->getRoutes();
|
||||
|
||||
if (empty($routes)) {
|
||||
$output->writeln('<info>Nenhuma rota encontrada.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['Método', 'URI', 'Handler']);
|
||||
|
||||
foreach ($routes as $route) {
|
||||
[$method, $uri, $handler] = $route;
|
||||
|
||||
$handlerName = 'Closure';
|
||||
if (is_array($handler)) {
|
||||
if (is_object($handler[0])) {
|
||||
$handlerName = get_class($handler[0]) . '@' . $handler[1];
|
||||
} elseif (is_string($handler[0])) {
|
||||
$handlerName = $handler[0] . '@' . $handler[1];
|
||||
}
|
||||
} elseif (is_string($handler)) {
|
||||
$handlerName = $handler;
|
||||
}
|
||||
|
||||
$table->addRow([
|
||||
$method,
|
||||
$uri,
|
||||
$handlerName
|
||||
]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class StorageLinkCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'storage:link';
|
||||
protected static $defaultDescription = 'Create the symbolic link from "public/storage" to "storage/uploads"';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$root = dirname(__DIR__, 3);
|
||||
$target = $root . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'uploads';
|
||||
$link = $root . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'storage';
|
||||
|
||||
if (!is_dir($target)) {
|
||||
if (!mkdir($target, 0755, true)) {
|
||||
$output->writeln('<error>Could not create directory: ' . $target . '</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
$output->writeln('<info>Created directory: ' . $target . '</info>');
|
||||
}
|
||||
|
||||
if (file_exists($link) || is_link($link)) {
|
||||
$output->writeln('<error>The "public/storage" already exists (as a file, directory or link).</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||
// On Windows, try Junction first as it doesn't require admin privileges
|
||||
$command = sprintf('mklink /J "%s" "%s"', $link, $target);
|
||||
exec($command, $cmdOutput, $returnVar);
|
||||
|
||||
if ($returnVar === 0) {
|
||||
$output->writeln('<info>The [public/storage] link has been connected to [storage/uploads] (Junction).</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
// Fallback to symlink if junction failed (though unlikely)
|
||||
if (@symlink($target, $link)) {
|
||||
$output->writeln('<info>The [public/storage] link has been connected to [storage/uploads] (Symlink).</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
} else {
|
||||
// On Linux/Unix
|
||||
if (@symlink($target, $link)) {
|
||||
$output->writeln('<info>The [public/storage] link has been connected to [storage/uploads].</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('<error>The links could not be created. Please check permissions.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class UpCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'up';
|
||||
protected static $defaultDescription = 'Tira a aplicação do modo de manutenção';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$downFile = dirname(__DIR__, 3) . '/storage/framework/down';
|
||||
|
||||
if (!file_exists($downFile)) {
|
||||
$output->writeln('<comment>A aplicação já está ativa.</comment>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
if (unlink($downFile)) {
|
||||
$output->writeln('<info>Aplicação agora está ativa.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$output->writeln('<error>Falha ao tirar a aplicação do modo de manutenção.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Modules\Auth\Models\User;
|
||||
|
||||
class UserDeleteCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'user:delete';
|
||||
protected static $defaultDescription = 'Remove um usuário do sistema';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('user', InputArgument::REQUIRED, 'O ID ou E-mail do usuário a ser removido')
|
||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Confirmar a remoção sem prompt');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$userInput = $input->getArgument('user');
|
||||
$force = $input->getOption('force');
|
||||
|
||||
$user = is_numeric($userInput)
|
||||
? User::find($userInput)
|
||||
: User::where('users_email', $userInput)->first();
|
||||
|
||||
if (!$user) {
|
||||
$output->writeln("<error>Usuário '{$userInput}' não encontrado.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (!$force) {
|
||||
$output->writeln("<comment>Você tem certeza que deseja remover o usuário '{$user->users_name}' ({$user->users_email})?</comment>");
|
||||
$output->writeln("<info>Use a opção --force para confirmar.</info>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$user->delete();
|
||||
$output->writeln("<info>Usuário '{$user->users_name}' removido com sucesso!</info>");
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro ao remover usuário: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Modules\Auth\Models\User;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
class UserListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'user:list';
|
||||
protected static $defaultDescription = 'Lista todos os usuários cadastrados no sistema';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$users = User::all();
|
||||
|
||||
if ($users->isEmpty()) {
|
||||
$output->writeln('<info>Nenhum usuário encontrado.</info>');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$table = new Table($output);
|
||||
$table->setHeaders(['ID', 'ID Bus', 'Nome', 'Email', 'Status', 'Criado em']);
|
||||
|
||||
foreach ($users as $user) {
|
||||
$table->addRow([
|
||||
$user->users_id,
|
||||
$user->users_bus_id ?? '-',
|
||||
$user->users_name,
|
||||
$user->users_email,
|
||||
($user->users_status === 'active') ? '<info>Ativo</info>' : '<comment>' . ucfirst($user->users_status) . '</comment>',
|
||||
$user->created_at
|
||||
]);
|
||||
}
|
||||
|
||||
$table->render();
|
||||
$output->writeln("<info>Total de usuários: " . $users->count() . "</info>");
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Modules\Auth\Models\User;
|
||||
|
||||
class UserPasswordCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'user:password';
|
||||
protected static $defaultDescription = 'Altera a senha de um usuário cadastrado no sistema';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('user', InputArgument::REQUIRED, 'O ID ou E-mail do usuário')
|
||||
->addArgument('password', InputArgument::REQUIRED, 'A nova senha');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$userInput = $input->getArgument('user');
|
||||
$newPassword = $input->getArgument('password');
|
||||
|
||||
$user = is_numeric($userInput)
|
||||
? User::find($userInput)
|
||||
: User::where('users_email', $userInput)->first();
|
||||
|
||||
if (!$user) {
|
||||
$output->writeln("<error>Usuário '{$userInput}' não encontrado.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$user->users_password = password_hash($newPassword, PASSWORD_DEFAULT);
|
||||
$user->save();
|
||||
$output->writeln("<info>Senha do usuário '{$user->users_name}' alterada com sucesso!</info>");
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro ao alterar senha: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\Question;
|
||||
use Modules\Auth\Models\User;
|
||||
|
||||
class UserRegisterCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'user:register';
|
||||
protected static $defaultDescription = 'Registra um novo usuário de forma interativa';
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$helper = $this->getHelper('question');
|
||||
|
||||
$output->writeln('<info>Cadastro de Novo Usuário</info>');
|
||||
$output->writeln('-------------------------');
|
||||
|
||||
// Name
|
||||
$nameQuestion = new Question('Nome completo: ');
|
||||
$name = $helper->ask($input, $output, $nameQuestion);
|
||||
if (empty($name)) {
|
||||
$output->writeln('<error>O nome é obrigatório.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
// Email
|
||||
$emailQuestion = new Question('E-mail: ');
|
||||
$email = $helper->ask($input, $output, $emailQuestion);
|
||||
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$output->writeln('<error>E-mail inválido ou vazio.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
if (User::where('users_email', $email)->exists()) {
|
||||
$output->writeln("<error>Já existe um usuário com o e-mail {$email}.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
// Password
|
||||
$passwordQuestion = new Question('Senha: ');
|
||||
$passwordQuestion->setHidden(true);
|
||||
$passwordQuestion->setHiddenFallback(false);
|
||||
$password = $helper->ask($input, $output, $passwordQuestion);
|
||||
|
||||
if (strlen($password) < 6) {
|
||||
$output->writeln('<error>A senha deve ter pelo menos 6 caracteres.</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
// Bus ID
|
||||
$busIdQuestion = new Question('ID Bus (opcional): ');
|
||||
$busId = $helper->ask($input, $output, $busIdQuestion);
|
||||
|
||||
try {
|
||||
$user = new User();
|
||||
$user->users_name = $name;
|
||||
$user->users_email = $email;
|
||||
$user->users_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$user->users_role = 'user';
|
||||
$user->users_bus_id = $busId;
|
||||
$user->users_status = 'active';
|
||||
$user->save();
|
||||
|
||||
$output->writeln("\n<info>Usuário '{$name}' cadastrado com sucesso!</info>");
|
||||
$output->writeln("ID: {$user->users_id}");
|
||||
$output->writeln("E-mail: {$user->users_email}");
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro ao cadastrar usuário: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Modules\Auth\Models\User;
|
||||
|
||||
class UserRoleCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'user:role';
|
||||
protected static $defaultDescription = 'Altera o nível de acesso (role) de um usuário';
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('user', InputArgument::REQUIRED, 'O ID ou E-mail do usuário')
|
||||
->addArgument('role', InputArgument::REQUIRED, 'O novo nível de acesso (ex: user, admin, super_admin)');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$userInput = $input->getArgument('user');
|
||||
$newRole = strtolower($input->getArgument('role'));
|
||||
|
||||
$user = is_numeric($userInput)
|
||||
? User::find($userInput)
|
||||
: User::where('users_email', $userInput)->first();
|
||||
|
||||
if (!$user) {
|
||||
$output->writeln("<error>Usuário '{$userInput}' não encontrado.</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$oldRole = $user->users_role;
|
||||
$user->users_role = $newRole;
|
||||
$user->save();
|
||||
|
||||
$output->writeln("<info>Nível de acesso do usuário '{$user->users_name}' alterado com sucesso!</info>");
|
||||
$output->writeln("De: <comment>{$oldRole}</comment> para: <info>{$newRole}</info>");
|
||||
|
||||
return Command::SUCCESS;
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>Erro ao alterar nível de acesso: " . $e->getMessage() . "</error>");
|
||||
return Command::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user