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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
strategy:
fail-fast: true
matrix:
stack: [blade, react, vue, svelte, api]
stack: [blade, react, vue, svelte, api, livewire, livewire-functional]
laravel: [11]
args: ["", --pest, --module=Authentication]
include:
Expand Down
20 changes: 17 additions & 3 deletions src/Console/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#[AsCommand(name: 'flextra:install')]
final class InstallCommand extends Command implements PromptsForMissingInput
{
use InstallModuleApi, InstallModuleBlade, InstallReactWithInertia, InstallSvelteWithInertia, InstallVueWithInertia;
use InstallModuleApi, InstallModuleBlade, InstallModuleLivewire, InstallReactWithInertia, InstallSvelteWithInertia, InstallVueWithInertia;

/**
* The console command signature and name.
Expand Down Expand Up @@ -79,11 +79,19 @@ public function handle(): ?int
return $this->installBladeModule($this->moduleName);
}

if ($this->argument('stack') === 'livewire') {
return $this->installLivewireModule($this->moduleName, false);
}

if ($this->argument('stack') === 'livewire-functional') {
return $this->installLivewireModule($this->moduleName, true);
}

if ($this->argument('stack') === 'api') {
return $this->installApiModule($this->moduleName);
}

$this->components->error('Invalid stack. Supported stacks are [react], [vue], [svelte] and [blade].');
$this->components->error('Invalid stack. Supported stacks are [react], [vue], [svelte], [livewire], [livewire-functional] and [blade].');

return 1;
}
Expand Down Expand Up @@ -162,6 +170,8 @@ protected function promptForMissingArgumentsUsing(): array
'react' => 'Inertia React with Laravel Modules',
'vue' => 'Inertia Vue with Laravel Modules',
'svelte' => 'Inertia Svelte with Laravel Modules',
'livewire' => 'Livewire (Volt Class API) with Alpine and Laravel Modules',
'livewire-functional' => 'Livewire (Functional API) with Alpine and Laravel Modules',
'api' => 'API with Laravel Modules',
],
scroll: 6,
Expand Down Expand Up @@ -196,7 +206,7 @@ protected function afterPromptingForMissingArguments(InputInterface $input, Outp
],
hint: 'Use the space bar to select options.'
))->each(fn ($option) => $input->setOption($option, true));
} elseif ($stack === 'blade') {
} elseif (in_array($stack, ['blade', 'livewire', 'livewire-functional'])) {
$input->setOption('dark', confirm(
label: 'Would you like dark mode support?',
default: false
Expand All @@ -212,13 +222,16 @@ protected function afterPromptingForMissingArguments(InputInterface $input, Outp

/**
* install module-inertia-react tests from stub
*
* @throws JsonException
*/
protected function installTests(): bool
{
(new Filesystem)->ensureDirectoryExists(base_path('tests/Feature'));

$stubStack = match ($this->argument('stack')) {
'livewire' => 'livewire-common',
'livewire-functional' => 'livewire-common',
'api' => 'api-module',
'blade' => 'blade-module',
default => 'inertia-php',
Expand Down Expand Up @@ -490,6 +503,7 @@ private function removeDarkClasses(Finder $finder): void

/**
* Install Module Dependencies
*
* @throws JsonException
*/
private function installModuleDependencies(bool $api = false): void
Expand Down
215 changes: 106 additions & 109 deletions src/Console/InstallModuleApi.php
Original file line number Diff line number Diff line change
@@ -1,109 +1,106 @@
<?php

namespace TooInfinity\Flextra\Console;

use Illuminate\Filesystem\Filesystem;
use JsonException;

trait InstallModuleApi
{
/**
* Install the API flextra stack with Laravel Modules.
*
* @param $moduleName
* @return int|null
* @throws JsonException
*/
protected function installApiModule($moduleName): ?int
{
$this->runCommands(['php artisan install:api']);
$this->installModuleDependencies(true);

$files = new Filesystem;

// Controllers...
$this->copyModuleFilesWithNamespace(
$moduleName,
__DIR__.'/../../stubs/api-module/app/Http/Controllers/Auth',
base_path('Modules/'.$moduleName.'/app/Http/Controllers')
);

// Middleware...
$files->copyDirectory(__DIR__.'/../../stubs/api-module/app/Http/Middleware', app_path('Http/Middleware'));

$this->installMiddlewareAliases([
'verified' => '\App\Http\Middleware\EnsureEmailIsVerified::class',
]);

$this->installMiddleware([
'\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class',
], 'api', 'prepend');

// Requests...
$this->copyModuleFilesWithNamespace(
$moduleName,
__DIR__.'/../../stubs/api-module/app/Http/Requests/Auth',
base_path('Modules/'.$moduleName.'/app/Http/Requests')
);

// Providers...
$files->copyDirectory(__DIR__.'/../../stubs/api-module/app/Providers', app_path('Providers'));

// Routes...
$this->copyFileWithNamespace($moduleName, __DIR__.'/../../stubs/api-module/routes/web.php', base_path('Modules/'.$moduleName.'/routes/web.php'));
$this->copyFileWithNamespace($moduleName, __DIR__.'/../../stubs/api-module/routes/auth.php', base_path('Modules/'.$moduleName.'/routes/auth.php'));
$this->copyFileWithNamespace($moduleName, __DIR__.'/../../stubs/api-module/routes/api.php', base_path('Modules/'.$moduleName.'/routes/api.php'));

// Configuration...
$files->copyDirectory(__DIR__.'/../../stubs/api-module/config', config_path());

// Environment...
if (! $files->exists(base_path('.env'))) {
copy(base_path('.env.example'), base_path('.env'));
}

file_put_contents(
base_path('.env'),
preg_replace('/APP_URL=(.*)/', 'APP_URL=http://localhost:8000'.PHP_EOL.'FRONTEND_URL=http://localhost:3000', file_get_contents(base_path('.env')))
);

// Tests...
if (! $this->installTests()) {
return 1;
}

$files->delete(base_path('tests/Feature/Auth/PasswordConfirmationTest.php'));

// Cleaning...
$this->removeScaffoldingUnnecessaryForApis();

$this->components->info('Flextra Api for '.$moduleName.' Module scaffolding installed successfully.');

return 0;
}

/**
* Remove any application scaffolding that isn't needed for APIs.
*
* @return void
*/
protected function removeScaffoldingUnnecessaryForApis(): void
{
$files = new Filesystem;

// Remove frontend related files...
$files->delete(base_path('package.json'));
$files->delete(base_path('vite.config.js'));
$files->delete(base_path('tailwind.config.js'));
$files->delete(base_path('postcss.config.js'));

// Remove Laravel "welcome" view...
$files->delete(resource_path('views/welcome.blade.php'));
$files->put(resource_path('views/.gitkeep'), PHP_EOL);

// Remove CSS and JavaScript directories...
$files->deleteDirectory(resource_path('css'));
$files->deleteDirectory(resource_path('js'));
}

}
<?php

declare(strict_types=1);

namespace TooInfinity\Flextra\Console;

use Illuminate\Filesystem\Filesystem;
use JsonException;

trait InstallModuleApi
{
/**
* Install the API flextra stack with Laravel Modules.
*
* @throws JsonException
*/
protected function installApiModule($moduleName): ?int
{
$this->runCommands(['php artisan install:api']);
$this->installModuleDependencies(true);

$files = new Filesystem;

// Controllers...
$this->copyModuleFilesWithNamespace(
$moduleName,
__DIR__.'/../../stubs/api-module/app/Http/Controllers/Auth',
base_path('Modules/'.$moduleName.'/app/Http/Controllers')
);

// Middleware...
$files->copyDirectory(__DIR__.'/../../stubs/api-module/app/Http/Middleware', app_path('Http/Middleware'));

$this->installMiddlewareAliases([
'verified' => '\App\Http\Middleware\EnsureEmailIsVerified::class',
]);

$this->installMiddleware([
'\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class',
], 'api', 'prepend');

// Requests...
$this->copyModuleFilesWithNamespace(
$moduleName,
__DIR__.'/../../stubs/api-module/app/Http/Requests/Auth',
base_path('Modules/'.$moduleName.'/app/Http/Requests')
);

// Providers...
$files->copyDirectory(__DIR__.'/../../stubs/api-module/app/Providers', app_path('Providers'));

// Routes...
$this->copyFileWithNamespace($moduleName, __DIR__.'/../../stubs/api-module/routes/web.php', base_path('Modules/'.$moduleName.'/routes/web.php'));
$this->copyFileWithNamespace($moduleName, __DIR__.'/../../stubs/api-module/routes/auth.php', base_path('Modules/'.$moduleName.'/routes/auth.php'));
$this->copyFileWithNamespace($moduleName, __DIR__.'/../../stubs/api-module/routes/api.php', base_path('Modules/'.$moduleName.'/routes/api.php'));

// Configuration...
$files->copyDirectory(__DIR__.'/../../stubs/api-module/config', config_path());

// Environment...
if (! $files->exists(base_path('.env'))) {
copy(base_path('.env.example'), base_path('.env'));
}

file_put_contents(
base_path('.env'),
preg_replace('/APP_URL=(.*)/', 'APP_URL=http://localhost:8000'.PHP_EOL.'FRONTEND_URL=http://localhost:3000', file_get_contents(base_path('.env')))
);

// Tests...
if (! $this->installTests()) {
return 1;
}

$files->delete(base_path('tests/Feature/Auth/PasswordConfirmationTest.php'));

// Cleaning...
$this->removeScaffoldingUnnecessaryForApis();

$this->components->info('Flextra Api for '.$moduleName.' Module scaffolding installed successfully.');

return 0;
}

/**
* Remove any application scaffolding that isn't needed for APIs.
*/
protected function removeScaffoldingUnnecessaryForApis(): void
{
$files = new Filesystem;

// Remove frontend related files...
$files->delete(base_path('package.json'));
$files->delete(base_path('vite.config.js'));
$files->delete(base_path('tailwind.config.js'));
$files->delete(base_path('postcss.config.js'));

// Remove Laravel "welcome" view...
$files->delete(resource_path('views/welcome.blade.php'));
$files->put(resource_path('views/.gitkeep'), PHP_EOL);

// Remove CSS and JavaScript directories...
$files->deleteDirectory(resource_path('css'));
$files->deleteDirectory(resource_path('js'));
}
}
Loading