feat: Complete Woles Framework v1.0 with enterprise-grade UI
- Add comprehensive error handling system with custom error pages - Implement professional enterprise-style design with Tailwind CSS - Create modular HMVC architecture with clean separation of concerns - Add security features: CSRF protection, XSS filtering, Argon2ID hashing - Include CLI tools for development workflow - Add error reporting dashboard with system monitoring - Implement responsive design with consistent slate color scheme - Replace all emoji icons with professional SVG icons - Add comprehensive test suite with PHPUnit - Include database migrations and seeders - Add proper exception handling with fallback pages - Implement template engine with custom syntax support - Add helper functions and facades for clean code - Include proper logging and debugging capabilities
This commit is contained in:
40
app/Core/Commands/CommandFactory.php
Normal file
40
app/Core/Commands/CommandFactory.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core\Commands;
|
||||
|
||||
/**
|
||||
* Woles Command Factory
|
||||
* Factory for creating command instances
|
||||
*/
|
||||
class CommandFactory
|
||||
{
|
||||
/**
|
||||
* Create command instance
|
||||
*/
|
||||
public static function create(string $command): object
|
||||
{
|
||||
switch ($command) {
|
||||
case 'make:module':
|
||||
return new MakeModuleCommand();
|
||||
case 'make:controller':
|
||||
return new MakeControllerCommand();
|
||||
case 'make:model':
|
||||
return new MakeModelCommand();
|
||||
case 'serve':
|
||||
return new ServeCommand();
|
||||
case 'migrate':
|
||||
return new MigrateCommand();
|
||||
case 'migrate:rollback':
|
||||
return new MigrateCommand();
|
||||
case 'migrate:status':
|
||||
return new MigrateCommand();
|
||||
case 'seed':
|
||||
return new SeedCommand();
|
||||
case 'key:generate':
|
||||
return new KeyGenerateCommand();
|
||||
case 'help':
|
||||
default:
|
||||
return new HelpCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
55
app/Core/Commands/HelpCommand.php
Normal file
55
app/Core/Commands/HelpCommand.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core\Commands;
|
||||
|
||||
/**
|
||||
* Woles Help Command
|
||||
* CLI command to show help information
|
||||
*/
|
||||
class HelpCommand
|
||||
{
|
||||
private array $commands = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->commands = [
|
||||
'make:module' => 'Create a new module',
|
||||
'make:controller' => 'Create a new controller',
|
||||
'make:model' => 'Create a new model',
|
||||
'serve' => 'Start development server',
|
||||
'migrate' => 'Run database migrations',
|
||||
'migrate:rollback' => 'Rollback last migration batch',
|
||||
'migrate:status' => 'Show migration status',
|
||||
'seed' => 'Run database seeders',
|
||||
'key:generate' => 'Generate application key',
|
||||
'key:generate-show' => 'Generate and show application key',
|
||||
'help' => 'Show available commands'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the command
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
echo "Woles Framework Artisan CLI\n\n";
|
||||
echo "Available commands:\n";
|
||||
|
||||
foreach ($this->commands as $command => $description) {
|
||||
echo " " . str_pad($command, 20) . " {$description}\n";
|
||||
}
|
||||
|
||||
echo "\nExamples:\n";
|
||||
echo " php woles make:module Blog\n";
|
||||
echo " php woles make:controller PostController Blog\n";
|
||||
echo " php woles make:model Post Blog\n";
|
||||
echo " php woles serve\n";
|
||||
echo " php woles migrate\n";
|
||||
echo " php woles migrate:rollback\n";
|
||||
echo " php woles migrate:status\n";
|
||||
echo " php woles seed\n";
|
||||
echo " php woles seed UserSeeder\n";
|
||||
echo " php woles key:generate\n";
|
||||
echo " php woles key:generate-show\n";
|
||||
}
|
||||
}
|
||||
52
app/Core/Commands/KeyGenerateCommand.php
Normal file
52
app/Core/Commands/KeyGenerateCommand.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core\Commands;
|
||||
|
||||
/**
|
||||
* KeyGenerateCommand
|
||||
* Generate and set APP_KEY in .env
|
||||
*/
|
||||
class KeyGenerateCommand
|
||||
{
|
||||
/**
|
||||
* Execute the command
|
||||
*/
|
||||
public function execute(bool $showOnly = false): void
|
||||
{
|
||||
$key = bin2hex(random_bytes(32)); // 64 hex chars
|
||||
|
||||
if ($showOnly) {
|
||||
echo $key . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$envPath = __DIR__ . '/../../../.env';
|
||||
$examplePath = __DIR__ . '/../../../env.example';
|
||||
|
||||
// If .env doesn't exist, try to copy from example
|
||||
if (!file_exists($envPath)) {
|
||||
if (file_exists($examplePath)) {
|
||||
copy($examplePath, $envPath);
|
||||
} else {
|
||||
// Create minimal .env
|
||||
file_put_contents($envPath, "APP_NAME=NovaCore Framework\nAPP_ENV=production\nAPP_DEBUG=false\n");
|
||||
}
|
||||
}
|
||||
|
||||
$content = file_get_contents($envPath) ?: '';
|
||||
|
||||
// Replace or append APP_KEY
|
||||
if (preg_match('/^APP_KEY=.*/m', $content)) {
|
||||
$content = preg_replace('/^APP_KEY=.*/m', 'APP_KEY=' . $key, $content);
|
||||
} else {
|
||||
$content .= (str_ends_with($content, "\n") ? '' : "\n") . 'APP_KEY=' . $key . "\n";
|
||||
}
|
||||
|
||||
// Backup and write
|
||||
@copy($envPath, $envPath . '.bak');
|
||||
file_put_contents($envPath, $content);
|
||||
|
||||
echo "Application key set successfully.\n";
|
||||
echo "APP_KEY=" . $key . "\n";
|
||||
}
|
||||
}
|
||||
41
app/Core/Commands/MakeControllerCommand.php
Normal file
41
app/Core/Commands/MakeControllerCommand.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core\Commands;
|
||||
|
||||
class MakeControllerCommand
|
||||
{
|
||||
public function execute(string $name, string $module): void
|
||||
{
|
||||
if (!$name || !$module) {
|
||||
echo "Error: Controller name and module are required\n";
|
||||
echo "Usage: php artisan make:controller <ControllerName> <ModuleName>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$modulePath = __DIR__ . "/../../Modules/{$module}";
|
||||
|
||||
if (!is_dir($modulePath)) {
|
||||
echo "Error: Module '{$module}' does not exist\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$content = "<?php
|
||||
|
||||
namespace App\\Modules\\{$module};
|
||||
|
||||
use App\\Core\\Controller;
|
||||
|
||||
class {$name} extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return \$this->view('{$module}.view.index', [
|
||||
'title' => '{$module} - NovaCore Framework'
|
||||
]);
|
||||
}
|
||||
}";
|
||||
|
||||
file_put_contents("{$modulePath}/{$name}.php", $content);
|
||||
echo "Controller '{$name}' created in module '{$module}'!\n";
|
||||
}
|
||||
}
|
||||
34
app/Core/Commands/MakeModelCommand.php
Normal file
34
app/Core/Commands/MakeModelCommand.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core\Commands;
|
||||
|
||||
class MakeModelCommand
|
||||
{
|
||||
public function execute(string $name, string $module): void
|
||||
{
|
||||
if (!$name || !$module) {
|
||||
echo "Error: Model name and module are required\n";
|
||||
echo "Usage: php artisan make:model <ModelName> <ModuleName>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$modulePath = __DIR__ . "/../../Modules/{$module}";
|
||||
|
||||
if (!is_dir($modulePath)) {
|
||||
echo "Error: Module '{$module}' does not exist\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$content = "<?php
|
||||
|
||||
namespace App\\Modules\\{$module};
|
||||
|
||||
class {$name}
|
||||
{
|
||||
// Add your model methods here
|
||||
}";
|
||||
|
||||
file_put_contents("{$modulePath}/{$name}.php", $content);
|
||||
echo "Model '{$name}' created in module '{$module}'!\n";
|
||||
}
|
||||
}
|
||||
164
app/Core/Commands/MakeModuleCommand.php
Normal file
164
app/Core/Commands/MakeModuleCommand.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core\Commands;
|
||||
|
||||
/**
|
||||
* NovaCore Make Module Command
|
||||
* CLI command to create new modules
|
||||
*/
|
||||
class MakeModuleCommand
|
||||
{
|
||||
private string $modulesPath;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->modulesPath = __DIR__ . '/../../Modules';
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the command
|
||||
*/
|
||||
public function execute(string $moduleName): void
|
||||
{
|
||||
if (!$moduleName) {
|
||||
echo "Error: Module name is required\n";
|
||||
echo "Usage: php artisan make:module <ModuleName>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$modulePath = $this->modulesPath . '/' . $moduleName;
|
||||
$viewPath = "{$modulePath}/view";
|
||||
|
||||
// Create directories
|
||||
if (!is_dir($modulePath)) {
|
||||
mkdir($modulePath, 0755, true);
|
||||
}
|
||||
if (!is_dir($viewPath)) {
|
||||
mkdir($viewPath, 0755, true);
|
||||
}
|
||||
|
||||
// Create Controller
|
||||
$this->createController($moduleName, $modulePath);
|
||||
|
||||
// Create Model
|
||||
$this->createModel($moduleName, $modulePath);
|
||||
|
||||
// Create Routes
|
||||
$this->createRoutes($moduleName, $modulePath);
|
||||
|
||||
// Create View
|
||||
$this->createView($moduleName, $viewPath);
|
||||
|
||||
echo "Module '{$moduleName}' created successfully!\n";
|
||||
echo "Controller: {$modulePath}/Controller.php\n";
|
||||
echo "Model: {$modulePath}/Model.php\n";
|
||||
echo "Routes: {$modulePath}/routes.php\n";
|
||||
echo "View: {$viewPath}/index.php\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create controller file
|
||||
*/
|
||||
private function createController(string $moduleName, string $modulePath): void
|
||||
{
|
||||
$controllerContent = "<?php
|
||||
|
||||
namespace App\\Modules\\{$moduleName};
|
||||
|
||||
use App\\Core\\Controller;
|
||||
|
||||
/**
|
||||
* {$moduleName} Controller
|
||||
*/
|
||||
class Controller extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return \$this->view('{$moduleName}.view.index', [
|
||||
'title' => '{$moduleName} - NovaCore Framework'
|
||||
]);
|
||||
}
|
||||
}";
|
||||
|
||||
file_put_contents("{$modulePath}/Controller.php", $controllerContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create model file
|
||||
*/
|
||||
private function createModel(string $moduleName, string $modulePath): void
|
||||
{
|
||||
$modelContent = "<?php
|
||||
|
||||
namespace App\\Modules\\{$moduleName};
|
||||
|
||||
/**
|
||||
* {$moduleName} Model
|
||||
*/
|
||||
class Model
|
||||
{
|
||||
// Add your model methods here
|
||||
}";
|
||||
|
||||
file_put_contents("{$modulePath}/Model.php", $modelContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create routes file
|
||||
*/
|
||||
private function createRoutes(string $moduleName, string $modulePath): void
|
||||
{
|
||||
$routesContent = "<?php
|
||||
|
||||
/**
|
||||
* {$moduleName} Module Routes
|
||||
*/
|
||||
|
||||
\$router->get('/{$moduleName}', '{$moduleName}\\Controller@index');";
|
||||
|
||||
file_put_contents("{$modulePath}/routes.php", $routesContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create view file
|
||||
*/
|
||||
private function createView(string $moduleName, string $viewPath): void
|
||||
{
|
||||
$viewContent = "<!DOCTYPE html>
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta charset=\"UTF-8\">
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
|
||||
<title>{{ \$title }}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: #f8f9fa;
|
||||
margin: 0;
|
||||
padding: 2rem;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #667eea;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class=\"container\">
|
||||
<h1>{{ \$title }}</h1>
|
||||
<p>Welcome to the {$moduleName} module!</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>";
|
||||
|
||||
file_put_contents("{$viewPath}/index.php", $viewContent);
|
||||
}
|
||||
}
|
||||
45
app/Core/Commands/MigrateCommand.php
Normal file
45
app/Core/Commands/MigrateCommand.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core\Commands;
|
||||
|
||||
use App\Core\Database\Migrator;
|
||||
|
||||
/**
|
||||
* NovaCore Migrate Command
|
||||
* CLI command to run database migrations
|
||||
*/
|
||||
class MigrateCommand
|
||||
{
|
||||
private Migrator $migrator;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->migrator = new Migrator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the command
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
echo "Running database migrations...\n";
|
||||
$this->migrator->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback migrations
|
||||
*/
|
||||
public function rollback(): void
|
||||
{
|
||||
echo "Rolling back migrations...\n";
|
||||
$this->migrator->rollback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show migration status
|
||||
*/
|
||||
public function status(): void
|
||||
{
|
||||
$this->migrator->status();
|
||||
}
|
||||
}
|
||||
91
app/Core/Commands/SeedCommand.php
Normal file
91
app/Core/Commands/SeedCommand.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core\Commands;
|
||||
|
||||
use App\Core\Database\Seeder;
|
||||
|
||||
/**
|
||||
* NovaCore Seed Command
|
||||
* CLI command to run database seeders
|
||||
*/
|
||||
class SeedCommand
|
||||
{
|
||||
private string $seedersPath;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->seedersPath = __DIR__ . '/../../database/seeders';
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the command
|
||||
*/
|
||||
public function execute(string $seeder = null): void
|
||||
{
|
||||
if ($seeder) {
|
||||
$this->runSeeder($seeder);
|
||||
} else {
|
||||
$this->runAllSeeders();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all seeders
|
||||
*/
|
||||
private function runAllSeeders(): void
|
||||
{
|
||||
echo "Running database seeders...\n";
|
||||
|
||||
$seederFiles = glob($this->seedersPath . '/*.php');
|
||||
|
||||
foreach ($seederFiles as $file) {
|
||||
$filename = basename($file);
|
||||
$className = $this->getSeederClassName($filename);
|
||||
|
||||
require_once $file;
|
||||
|
||||
if (class_exists($className)) {
|
||||
$seeder = new $className();
|
||||
$seeder->run();
|
||||
}
|
||||
}
|
||||
|
||||
echo "Seeding completed successfully!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Run specific seeder
|
||||
*/
|
||||
private function runSeeder(string $seederName): void
|
||||
{
|
||||
$file = $this->seedersPath . '/' . $seederName . '.php';
|
||||
|
||||
if (!file_exists($file)) {
|
||||
echo "Error: Seeder '{$seederName}' not found\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$className = $this->getSeederClassName($seederName . '.php');
|
||||
|
||||
require_once $file;
|
||||
|
||||
if (!class_exists($className)) {
|
||||
echo "Error: Seeder class '{$className}' not found\n";
|
||||
return;
|
||||
}
|
||||
|
||||
echo "Running seeder: {$seederName}\n";
|
||||
$seeder = new $className();
|
||||
$seeder->run();
|
||||
echo "Seeder completed successfully!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get seeder class name
|
||||
*/
|
||||
private function getSeederClassName(string $filename): string
|
||||
{
|
||||
$name = pathinfo($filename, PATHINFO_FILENAME);
|
||||
return "Database\\Seeders\\{$name}";
|
||||
}
|
||||
}
|
||||
25
app/Core/Commands/ServeCommand.php
Normal file
25
app/Core/Commands/ServeCommand.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Core\Commands;
|
||||
|
||||
/**
|
||||
* NovaCore Serve Command
|
||||
* CLI command to start development server
|
||||
*/
|
||||
class ServeCommand
|
||||
{
|
||||
/**
|
||||
* Execute the command
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
$port = getenv('APP_PORT') ?: '8000';
|
||||
$host = getenv('APP_HOST') ?: 'localhost';
|
||||
|
||||
echo "NovaCore Framework development server starting...\n";
|
||||
echo "Server running at http://{$host}:{$port}\n";
|
||||
echo "Press Ctrl+C to stop the server\n\n";
|
||||
|
||||
exec("php -S {$host}:{$port} -t public");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user