This commit is contained in:
Sampanna Rimal
2024-09-04 12:22:04 +05:45
parent 53c0140f58
commit 82fab174dc
203 changed files with 4255 additions and 1343 deletions

View File

@ -2,8 +2,46 @@
All Notable changes to `laravel-modules` will be documented in this file.
## 11.0.10 - 2024-05-05
## Next
- [@dcblogdev](https://github.com/dcblogdev) Update controller, service, helper, and action methods
- [@omerbaflah](https://github.com/omerbaflah) Update service stubs
- [@omerbaflah](https://github.com/omerbaflah) Update action stubs
- [@AbdulkarimOmer](https://github.com/AbdulkarimOmer) Added invokable option into make-controller command
- [@dcblogdev](https://github.com/dcblogdev) Updated vite-module-loader.js to handle case when a modules does not have a vite.config.js file
- [@alissn](https://github.com/alissn) Added direction option to command module:seed
## 11.0.9 - 2024-04-30
- [@dcblogdev](https://github.com/dcblogdev) added make-event-provider command, modules come with event as default now
## 11.0.8 - 2024-04-29
- [@solomon-ochepa](https://github.com/solomon-ochepa) Remove custom namespaces from generator [factory and seeder]
- [@dcblogdev](https://github.com/dcblogdev) added make-action command
- [@dcblogdev](https://github.com/dcblogdev) added make-cast command
- [@dcblogdev](https://github.com/dcblogdev) added make-enum command
- [@dcblogdev](https://github.com/dcblogdev) added make-exception command
- [@dcblogdev](https://github.com/dcblogdev) added make-helper command
- [@dcblogdev](https://github.com/dcblogdev) added make-interface command
- [@dcblogdev](https://github.com/dcblogdev) added make-scope command
- [@dcblogdev](https://github.com/dcblogdev) added make-trait command
- [@dcblogdev](https://github.com/dcblogdev) added missing return type for make-service command
- [@dcblogdev](https://github.com/dcblogdev) updated config
## 11.0.7 - 2024-04-25
## Changes
- [@dcblogdev](https://github.com/dcblogdev) Force the config replacement option for composer 'APP_FOLDER_NAME', to be handled even when its not present.
- [@solomon-ochepa](https://github.com/solomon-ochepa) Path Namespace - generate a well-formatted StudlyCase namespace from paths
- [@korridor](https://github.com/korridor) Fixed public path for octane setup
- [@dcblogdev](https://github.com/dcblogdev) added invokable and force options into make-service command
- [@dcblogdev](https://github.com/dcblogdev) Restrict fresh migration to module scope
- [@kowston](https://github.com/kowston) Changed wording for command descriptions to be consistent
## 11.0.6 - 2024-04-21
- [@alissn](https://github.com/alissn) change package version to Pretty on php artisan about

View File

@ -111,23 +111,31 @@ return [
*/
'generator' => [
// app/
'actions' => ['path' => 'app/Actions', 'generate' => false],
'casts' => ['path' => 'app/Casts', 'generate' => false],
'channels' => ['path' => 'app/Broadcasting', 'generate' => false],
'command' => ['path' => 'app/Console', 'generate' => false],
'component-class' => ['path' => 'app/View/Components', 'generate' => false],
'emails' => ['path' => 'app/Emails', 'generate' => false],
'event' => ['path' => 'app/Events', 'generate' => false],
'enums' => ['path' => 'app/Enums', 'generate' => false],
'exceptions' => ['path' => 'app/Exceptions', 'generate' => false],
'jobs' => ['path' => 'app/Jobs', 'generate' => false],
'helpers' => ['path' => 'app/Helpers', 'generate' => false],
'interfaces' => ['path' => 'app/Interfaces', 'generate' => false],
'listener' => ['path' => 'app/Listeners', 'generate' => false],
'model' => ['path' => 'app/Models', 'generate' => false],
'notifications' => ['path' => 'app/Notifications', 'generate' => false],
'observer' => ['path' => 'app/Observers', 'generate' => false],
'policies' => ['path' => 'app/Policies', 'generate' => false],
'provider' => ['path' => 'app/Providers', 'generate' => true],
'route-provider' => ['path' => 'app/Providers', 'generate' => true],
'repository' => ['path' => 'app/Repositories', 'generate' => false],
'resource' => ['path' => 'app/Transformers', 'generate' => false],
'route-provider' => ['path' => 'app/Providers', 'generate' => true],
'rules' => ['path' => 'app/Rules', 'generate' => false],
'component-class' => ['path' => 'app/View/Components', 'generate' => false],
'service' => ['path' => 'app/Services', 'generate' => false],
'services' => ['path' => 'app/Services', 'generate' => false],
'scopes' => ['path' => 'app/Models/Scopes', 'generate' => false],
'traits' => ['path' => 'app/Traits', 'generate' => false],
// app/Http/
'controller' => ['path' => 'app/Http/Controllers', 'generate' => true],
@ -138,24 +146,24 @@ return [
'config' => ['path' => 'config', 'generate' => true],
// database/
'factory' => ['path' => 'database/factories', 'generate' => true],
'migration' => ['path' => 'database/migrations', 'generate' => true],
'seeder' => ['path' => 'database/seeders', 'namespace' => 'Database\Seeders', 'generate' => true],
'factory' => ['path' => 'database/factories', 'namespace' => 'Database\Factories', 'generate' => true],
'seeder' => ['path' => 'database/seeders', 'generate' => true],
// lang/
'lang' => ['path' => 'lang', 'generate' => false],
// resource/
'assets' => ['path' => 'resources/assets', 'generate' => true],
'views' => ['path' => 'resources/views', 'generate' => true],
'component-view' => ['path' => 'resources/views/components', 'generate' => false],
'views' => ['path' => 'resources/views', 'generate' => true],
// routes/
'routes' => ['path' => 'routes', 'generate' => true],
// tests/
'test-unit' => ['path' => 'tests/Unit', 'generate' => true],
'test-feature' => ['path' => 'tests/Feature', 'generate' => true],
'test-unit' => ['path' => 'tests/Unit', 'generate' => true],
],
],

View File

@ -23,15 +23,17 @@ async function collectModuleAssetsPaths(paths, modulesPath) {
// Check if the module is enabled (status is true)
if (moduleStatuses[moduleDir] === true) {
const viteConfigPath = path.join(modulesPath, moduleDir, 'vite.config.js');
const stat = await fs.stat(viteConfigPath);
if (stat.isFile()) {
try {
await fs.access(viteConfigPath);
// Import the module-specific Vite configuration
const moduleConfig = await import(viteConfigPath);
if (moduleConfig.paths && Array.isArray(moduleConfig.paths)) {
paths.push(...moduleConfig.paths);
}
} catch (error) {
// vite.config.js does not exist, skip this module
}
}
}

View File

@ -50,7 +50,7 @@ class ModelPruneCommand extends PruneCommand implements PromptsForMissingInput
}
$selected_item = multiselect(
label : 'What Module want to check?',
label : 'Select Modules',
options : [
self::ALL,
...array_keys(Module::all()),

View File

@ -78,7 +78,7 @@ abstract class BaseCommand extends Command implements PromptsForMissingInput
}
$selected_item = multiselect(
label : 'What Module want to check?',
label : 'Select Modules',
options : [
self::ALL,
...$modules,

View File

@ -1,6 +1,6 @@
<?php
namespace Nwidart\Modules\Commands;
namespace Nwidart\Modules\Commands\Database;
use Illuminate\Console\Command;
use Nwidart\Modules\Traits\ModuleCommandTrait;
@ -23,7 +23,7 @@ class MigrateFreshCommand extends Command
*
* @var string
*/
protected $description = 'Drop all database tables and re-run all migrations';
protected $description = 'Reset all database tables and re-run the modules migrations.';
/**
* Execute the console command.
@ -38,9 +38,7 @@ class MigrateFreshCommand extends Command
return E_ERROR;
}
$this->call('migrate:fresh');
$this->call('module:migrate', [
$this->call('module:migrate-refresh', [
'module' => $this->getModuleName(),
'--database' => $this->option('database'),
'--force' => $this->option('force'),
@ -55,7 +53,7 @@ class MigrateFreshCommand extends Command
*
* @return array
*/
protected function getArguments()
protected function getArguments(): array
{
return [
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
@ -67,7 +65,7 @@ class MigrateFreshCommand extends Command
*
* @return array
*/
protected function getOptions()
protected function getOptions(): array
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],

View File

@ -52,7 +52,7 @@ class MigrateRefreshCommand extends BaseCommand
*
* @return array
*/
protected function getOptions()
protected function getOptions(): array
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],

View File

@ -226,6 +226,7 @@ class SeedCommand extends BaseCommand
protected function getOptions()
{
return [
['direction', 'd', InputOption::VALUE_OPTIONAL, 'The direction of ordering.', 'asc'],
['class', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder.'],
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],

View File

@ -0,0 +1,77 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class ActionMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-action';
protected $description = 'Create a new action class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$filePath = GenerateConfigReader::read('actions')->getPath() ?? config('modules.paths.app_folder') . 'Actions';
return $path . $filePath . '/' . $this->getActionName() . '.php';
}
protected function getTemplateContents(): string
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'CLASS_NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClassNameWithoutNamespace(),
]))->render();
}
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of the action class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['invokable', 'i', InputOption::VALUE_NONE, 'Generate an invokable action class', null],
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getActionName(): array|string
{
return Str::studly($this->argument('name'));
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getActionName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.actions.namespace', 'Actions');
}
protected function getStubName(): string
{
return $this->option('invokable') === true ? '/action-invoke.stub' : '/action.stub';
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class CastMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-cast';
protected $description = 'Create a new Eloquent cast class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$filePath = GenerateConfigReader::read('casts')->getPath() ?? config('modules.paths.app_folder') . 'Casts';
return $path . $filePath . '/' . $this->getCastName() . '.php';
}
protected function getTemplateContents(): string
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'CLASS_NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClassNameWithoutNamespace(),
]))->render();
}
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of the cast class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getCastName(): array|string
{
return Str::studly($this->argument('name'));
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getCastName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.casts.namespace', 'Casts');
}
protected function getStubName(): string
{
return '/cast.stub';
}
}

View File

@ -90,6 +90,7 @@ class ControllerMakeCommand extends GeneratorCommand
return [
['plain', 'p', InputOption::VALUE_NONE, 'Generate a plain controller', null],
['api', null, InputOption::VALUE_NONE, 'Exclude the create and edit methods from the controller.'],
['invokable', 'i', InputOption::VALUE_NONE, 'Generate a single method, invokable controller class'],
];
}
@ -131,6 +132,8 @@ class ControllerMakeCommand extends GeneratorCommand
$stub = '/controller-plain.stub';
} elseif ($this->option('api') === true) {
$stub = '/controller-api.stub';
} elseif ($this->option('invokable') === true) {
$stub = '/controller.invokable.stub';
} else {
$stub = '/controller.stub';
}

View File

@ -0,0 +1,76 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class EnumMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-enum';
protected $description = 'Create a new enum class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$filePath = GenerateConfigReader::read('enums')->getPath() ?? config('modules.paths.app_folder') . 'Enums';
return $path . $filePath . '/' . $this->getEnumName() . '.php';
}
protected function getTemplateContents(): string
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'CLASS_NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClassNameWithoutNamespace(),
]))->render();
}
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of the enum class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getEnumName(): array|string
{
return Str::studly($this->argument('name'));
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getEnumName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.enums.namespace', 'Enums');
}
protected function getStubName(): string
{
return '/enum.stub';
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class EventProviderMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'module';
protected $name = 'module:make-event-provider';
protected $description = 'Create a new event service provider class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$filePath = GenerateConfigReader::read('provider')->getPath();
return $path . $filePath . '/' . $this->getEventServiceProviderName() . '.php';
}
protected function getTemplateContents(): string
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClassNameWithoutNamespace(),
]))->render();
}
protected function getArguments(): array
{
return [
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getEventServiceProviderName(): array|string
{
return Str::studly('EventServiceProvider');
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getEventServiceProviderName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.provider.namespace')
?? ltrim(config('modules.paths.generator.provider.path', 'Providers'), config('modules.paths.app_folder', ''));
}
protected function getStubName(): string
{
return '/event-provider.stub';
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class ExceptionMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-exception';
protected $description = 'Create a new exception class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$filePath = GenerateConfigReader::read('exceptions')->getPath() ?? config('modules.paths.app_folder') . 'Exceptions';
return $path . $filePath . '/' . $this->getExceptionName() . '.php';
}
protected function getTemplateContents(): string
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'CLASS_NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClassNameWithoutNamespace(),
]))->render();
}
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of the action class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['render', '', InputOption::VALUE_NONE, 'Create the exception with an empty render method', null],
['report', '', InputOption::VALUE_NONE, 'Create the exception with an empty report method', null],
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getExceptionName(): array|string
{
return Str::studly($this->argument('name'));
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getExceptionName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.exceptions.namespace', 'Exceptions');
}
protected function getStubName(): string
{
if ($this->option('render')) {
return $this->option('report')
? '/exception-render-report.stub'
: '/exception-render.stub';
}
return $this->option('report')
? '/exception-report.stub'
: '/exception.stub';
}
}

View File

@ -5,9 +5,12 @@ namespace Nwidart\Modules\Commands\Make;
use Illuminate\Console\Command;
use Nwidart\Modules\Exceptions\FileAlreadyExistException;
use Nwidart\Modules\Generators\FileGenerator;
use Nwidart\Modules\Traits\PathNamespace;
abstract class GeneratorCommand extends Command
{
use PathNamespace;
/**
* The name of 'name' argument.
*
@ -86,20 +89,8 @@ abstract class GeneratorCommand extends Command
*/
public function getClassNamespace($module)
{
$extra = str_replace($this->getClass(), '', $this->argument($this->argumentName));
$path_namespace = $this->path_namespace(str_replace($this->getClass(), '', $this->argument($this->argumentName)));
$extra = str_replace('/', '\\', $extra);
$namespace = $this->laravel['modules']->config('namespace');
$namespace .= '\\' . $module->getStudlyName();
$namespace .= '\\' . $this->getDefaultNamespace();
$namespace .= '\\' . $extra;
$namespace = str_replace('/', '\\', $namespace);
return trim($namespace, '\\');
return $this->module_namespace($module->getStudlyName(), $this->getDefaultNamespace() . ($path_namespace ? '\\' . $path_namespace : ''));
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class HelperMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-helper';
protected $description = 'Create a new helper class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$filePath = GenerateConfigReader::read('helpers')->getPath() ?? config('modules.paths.app_folder') . 'Helpers';
return $path . $filePath . '/' . $this->getHelperName() . '.php';
}
protected function getTemplateContents(): string
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'CLASS_NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClassNameWithoutNamespace(),
]))->render();
}
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of the helper class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['invokable', 'i', InputOption::VALUE_NONE, 'Generate an invokable class', null],
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getHelperName(): array|string
{
return Str::studly($this->argument('name'));
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getHelperName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.helpers.namespace', 'Helpers');
}
protected function getStubName(): string
{
return $this->option('invokable') === true ? '/helper-invoke.stub' : '/helper.stub';
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class InterfaceMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-interface';
protected $description = 'Create a new interface class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$filePath = GenerateConfigReader::read('interfaces')->getPath() ?? config('modules.paths.app_folder') . 'Interfaces';
return $path . $filePath . '/' . $this->getInterfaceName() . '.php';
}
protected function getTemplateContents(): string
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'CLASS_NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClassNameWithoutNamespace(),
]))->render();
}
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of the action class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getInterfaceName(): array|string
{
return Str::studly($this->argument('name'));
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getInterfaceName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.interfaces.namespace', 'Interfaces');
}
protected function getStubName(): string
{
return '/interface.stub';
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class ScopeMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-scope';
protected $description = 'Create a new scope class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$filePath = GenerateConfigReader::read('scopes')->getPath() ?? config('modules.paths.generator.model.path') . '/Scopes';
return $path . $filePath . '/' . $this->getScopeName() . '.php';
}
protected function getTemplateContents(): string
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'CLASS_NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClassNameWithoutNamespace(),
]))->render();
}
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of the scope class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getScopeName(): array|string
{
return Str::studly($this->argument('name'));
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getScopeName());
}
public function getDefaultNamespace(): string
{
$namespace = config('modules.paths.generator.model.path');
$parts = explode("/", $namespace);
$models = end($parts);
return $models.'\Scopes';
}
protected function getStubName(): string
{
return '/scope.stub';
}
}

View File

@ -25,7 +25,7 @@ class SeedMakeCommand extends GeneratorCommand
/**
* The console command description.
*/
protected $description = 'Generate new seeder for the specified module.';
protected $description = 'Create a new seeder for the specified module.';
/**
* Get the console command arguments.

View File

@ -7,6 +7,7 @@ use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class ServiceMakeCommand extends GeneratorCommand
{
@ -14,15 +15,15 @@ class ServiceMakeCommand extends GeneratorCommand
protected $argumentName = 'name';
protected $name = 'module:make-service';
protected $description = 'Generate a service class for the specified module.';
protected $description = 'Create a new service class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$servicePath = GenerateConfigReader::read('service');
$filePath = GenerateConfigReader::read('services')->getPath() ?? config('modules.paths.app_folder') . 'Services';
return $path . $servicePath->getPath() . '/' . $this->getServiceName() . '.php';
return $path . $filePath . '/' . $this->getServiceName() . '.php';
}
protected function getTemplateContents(): string
@ -43,6 +44,17 @@ class ServiceMakeCommand extends GeneratorCommand
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['invokable', 'i', InputOption::VALUE_NONE, 'Generate an invokable service class', null],
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getServiceName(): array|string
{
return Str::studly($this->argument('name'));
@ -55,12 +67,11 @@ class ServiceMakeCommand extends GeneratorCommand
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.service.namespace')
?? ltrim(config('modules.paths.generator.service.path', 'Services'), config('modules.paths.app_folder'));
return config('modules.paths.generator.services.namespace', 'Services');
}
protected function getStubName(): string
{
return '/service.stub';
return $this->option('invokable') === true ? '/service-invoke.stub' : '/service.stub';
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class TraitMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-trait';
protected $description = 'Create a new trait class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$filePath = GenerateConfigReader::read('traits')->getPath() ?? config('modules.paths.app_folder') . 'Traits';
return $path . $filePath . '/' . $this->getTraitName() . '.php';
}
protected function getTemplateContents(): string
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'CLASS_NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClassNameWithoutNamespace(),
]))->render();
}
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of the trait class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['force', 'f', InputOption::VALUE_NONE, 'su.'],
];
}
protected function getTraitName(): array|string
{
return Str::studly($this->argument('name'));
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getTraitName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.traits.namespace', 'Traits');
}
protected function getStubName(): string
{
return '/trait.stub';
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace $CLASS_NAMESPACE$;
class $CLASS$
{
public function __invoke()
{
//
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace $CLASS_NAMESPACE$;
class $CLASS$
{
public function handle()
{
//
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace $CLASS_NAMESPACE$;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
class $CLASS$ implements CastsAttributes
{
/**
* Cast the given value.
*
* @param array<string, mixed> $attributes
*/
public function get(Model $model, string $key, mixed $value, array $attributes): mixed
{
return $value;
}
/**
* Prepare the given value for storage.
*
* @param array<string, mixed> $attributes
*/
public function set(Model $model, string $key, mixed $value, array $attributes): mixed
{
return $value;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace {{ namespace }};
namespace $CLASS_NAMESPACE$;
use App\Http\Controllers\Controller;
class $CLASS$ extends Controller
{
/**
* Handle the incoming request.
*/
public function __invoke(Request $request)
{
//
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace $CLASS_NAMESPACE$;
enum $CLASS$
{
//
}

View File

@ -0,0 +1,32 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class $CLASS$ extends ServiceProvider
{
/**
* The event handler mappings for the application.
*
* @var array<string, array<int, string>>
*/
protected $listen = [];
/**
* Indicates if events should be discovered.
*
* @var bool
*/
protected static $shouldDiscoverEvents = true;
/**
* Configure the proper event listeners for email verification.
*
* @return void
*/
protected function configureEmailVerification(): void
{
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace $CLASS_NAMESPACE$;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class $CLASS$ extends Exception
{
/**
* Report the exception.
*/
public function report(): void
{
//
}
/**
* Render the exception as an HTTP response.
*/
public function render(Request $request): Response
{
//
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace $CLASS_NAMESPACE$;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class $CLASS$ extends Exception
{
/**
* Render the exception as an HTTP response.
*/
public function render(Request $request): Response
{
//
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace $CLASS_NAMESPACE$;
use Exception;
class $CLASS$ extends Exception
{
/**
* Report the exception.
*/
public function report(): void
{
//
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace $CLASS_NAMESPACE$;
use Exception;
class $CLASS$ extends Exception
{
//
}

View File

@ -0,0 +1,11 @@
<?php
namespace $CLASS_NAMESPACE$;
class $CLASS$
{
public function __invoke()
{
//
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace $CLASS_NAMESPACE$;
class $CLASS$
{
public function handle()
{
//
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace $CLASS_NAMESPACE$;
class $CLASS$
{
}

View File

@ -29,6 +29,7 @@ class $CLASS$ extends ServiceProvider
*/
public function register(): void
{
$this->app->register(EventServiceProvider::class);
$this->app->register(RouteServiceProvider::class);
}

View File

@ -0,0 +1,18 @@
<?php
namespace $CLASS_NAMESPACE$;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class $CLASS$ implements Scope
{
/**
* Apply the scope to a given Eloquent query builder.
*/
public function apply(Builder $builder, Model $model): void
{
//
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace $CLASS_NAMESPACE$;
class $CLASS$
{
public function __invoke()
{
//
}
}

View File

@ -4,7 +4,7 @@ namespace $CLASS_NAMESPACE$;
class $CLASS$
{
public function __construct()
public function handle()
{
//
}

View File

@ -0,0 +1,8 @@
<?php
namespace $CLASS_NAMESPACE$;
trait $CLASS$
{
//
}

View File

@ -10,9 +10,12 @@ use Nwidart\Modules\Contracts\ActivatorInterface;
use Nwidart\Modules\FileRepository;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\PathNamespace;
class ModuleGenerator extends Generator
{
use PathNamespace;
/**
* The module name will created.
*
@ -89,7 +92,7 @@ class ModuleGenerator extends Generator
* @var array
*/
protected array $author = [
'name', 'email'
'name', 'email',
];
/**
@ -296,7 +299,7 @@ class ModuleGenerator extends Generator
* @param string|null $email
* @return $this
*/
function setAuthor(string $name = null, string $email = null)
public function setAuthor(string $name = null, string $email = null)
{
$this->author['name'] = $name;
$this->author['email'] = $email;
@ -310,7 +313,7 @@ class ModuleGenerator extends Generator
* @param string|null $vendor
* @return $this
*/
function setVendor(string $vendor = null)
public function setVendor(string $vendor = null)
{
$this->vendor = $vendor;
@ -470,6 +473,25 @@ class ModuleGenerator extends Generator
);
}
$eventGeneratorConfig = GenerateConfigReader::read('event-provider');
if (
(is_null($eventGeneratorConfig->getPath()) && $providerGenerator->generate())
|| (!is_null($eventGeneratorConfig->getPath()) && $eventGeneratorConfig->generate())
) {
$this->console->call('module:make-event-provider', [
'module' => $this->getName(),
]);
} else {
if ($providerGenerator->generate()) {
// comment register EventServiceProvider
$this->filesystem->replaceInFile(
'$this->app->register(Event',
'// $this->app->register(Event',
$this->module->getModulePath($this->getName()) . DIRECTORY_SEPARATOR . $providerGenerator->getPath() . DIRECTORY_SEPARATOR . sprintf('%sServiceProvider.php', $this->getName())
);
}
}
$routeGeneratorConfig = GenerateConfigReader::read('route-provider');
if (
(is_null($routeGeneratorConfig->getPath()) && $providerGenerator->generate())
@ -533,6 +555,10 @@ class ModuleGenerator extends Generator
{
$replacements = $this->module->config('stubs.replacements');
if (!isset($replacements['composer']['APP_FOLDER_NAME'])) {
$replacements['composer'][] = 'APP_FOLDER_NAME';
}
if (!isset($replacements[$stub])) {
return [];
}
@ -629,17 +655,19 @@ class ModuleGenerator extends Generator
*/
protected function getModuleNamespaceReplacement()
{
return str_replace('\\', '\\\\', $this->module->config('namespace'));
return str_replace('\\', '\\\\', $this->module->config('namespace') ?? $this->path_namespace($this->module->config('paths.modules')));
}
/**
* Get replacement for $CONTROLLER_NAMESPACE$.
*
* @return string
*/
private function getControllerNamespaceReplacement(): string
{
return str_replace('/', '\\', $this->module->config('paths.generator.controller.namespace') ?: ltrim($this->module->config('paths.generator.controller.path', 'Controller'), config('modules.paths.app_folder')));
if ($this->module->config('paths.generator.controller.namespace')) {
return $this->module->config('paths.generator.controller.namespace');
} else {
return $this->path_namespace(ltrim($this->module->config('paths.generator.controller.path', 'app/Http/Controllers'), config('modules.paths.app_folder')));
}
}
/**

View File

@ -83,8 +83,8 @@ abstract class Module
{
$paths = [];
if (file_exists('build/manifest.json')) {
$files = json_decode(file_get_contents('build/manifest.json'), true);
if (file_exists(public_path('build/manifest.json'))) {
$files = json_decode(file_get_contents(public_path('build/manifest.json')), true);
if (is_array($files)) {
foreach ($files as $file) {

View File

@ -49,13 +49,20 @@ class ConsoleServiceProvider extends ServiceProvider
Commands\Database\SeedCommand::class,
// Make Commands
Commands\Make\ActionMakeCommand::class,
Commands\Make\CastMakeCommand::class,
Commands\Make\ChannelMakeCommand::class,
Commands\Make\CommandMakeCommand::class,
Commands\Make\ComponentClassMakeCommand::class,
Commands\Make\ComponentViewMakeCommand::class,
Commands\Make\ControllerMakeCommand::class,
Commands\Make\EventMakeCommand::class,
Commands\Make\EventProviderMakeCommand::class,
Commands\Make\EnumMakeCommand::class,
Commands\Make\ExceptionMakeCommand::class,
Commands\Make\FactoryMakeCommand::class,
Commands\Make\InterfaceMakeCommand::class,
Commands\Make\HelperMakeCommand::class,
Commands\Make\JobMakeCommand::class,
Commands\Make\ListenerMakeCommand::class,
Commands\Make\MailMakeCommand::class,
@ -71,8 +78,10 @@ class ConsoleServiceProvider extends ServiceProvider
Commands\Make\ResourceMakeCommand::class,
Commands\Make\RouteProviderMakeCommand::class,
Commands\Make\RuleMakeCommand::class,
Commands\Make\ScopeMakeCommand::class,
Commands\Make\SeedMakeCommand::class,
Commands\Make\ServiceMakeCommand::class,
Commands\Make\TraitMakeCommand::class,
Commands\Make\TestMakeCommand::class,
Commands\Make\ViewMakeCommand::class,
@ -87,7 +96,7 @@ class ConsoleServiceProvider extends ServiceProvider
Commands\LaravelModulesV6Migrator::class,
Commands\SetupCommand::class,
Commands\MigrateFreshCommand::class,
Commands\Database\MigrateFreshCommand::class,
]);
}
}

View File

@ -2,8 +2,12 @@
namespace Nwidart\Modules\Support\Config;
use Nwidart\Modules\Traits\PathNamespace;
class GeneratorPath
{
use PathNamespace;
private $path;
private $generate;
private $namespace;
@ -13,13 +17,14 @@ class GeneratorPath
if (is_array($config)) {
$this->path = $config['path'];
$this->generate = $config['generate'];
$this->namespace = $config['namespace'] ?? $this->convertPathToNamespace($config['path']);
$this->namespace = $config['namespace'] ?? $this->path_namespace(ltrim($config['path'], config('modules.paths.app_folder', '')));
return;
}
$this->path = $config;
$this->generate = (bool) $config;
$this->namespace = $config;
$this->namespace = $this->path_namespace(ltrim($config, config('modules.paths.app_folder', '')));
}
public function getPath()
@ -34,11 +39,6 @@ class GeneratorPath
public function getNamespace()
{
return $this->namespace;
}
private function convertPathToNamespace($path)
{
return str_replace('/', '\\', ltrim($path, config('modules.paths.app_folder', '')));
return $this->studly_namespace($this->namespace);
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Nwidart\Modules\Traits;
use Illuminate\Support\Str;
trait PathNamespace
{
/**
* Get a well-formatted StudlyCase representation of path components.
*/
public function studly_path(string $path, $directory_separator = '/'): string
{
return collect(explode($directory_separator, Str::of($path)
->replace("{$directory_separator}{$directory_separator}", $directory_separator)->trim($directory_separator)))
->map(fn ($path) => Str::studly($path))
->implode($directory_separator);
}
/**
* Get a well-formatted StudlyCase namespace.
*/
public function studly_namespace(string $namespace, $directory_separator = '\\'): string
{
return $this->studly_path($namespace, $directory_separator);
}
/**
* Get a well-formatted namespace from a given path.
*/
public function path_namespace(string $path): string
{
return Str::of($this->studly_path($path))->replace('/', '\\')->trim('\\');
}
/**
* Get a well-formatted StudlyCase namespace for a module, with an optional additional path.
*/
public function module_namespace(string $module, string $path = null): string
{
$module_namespace = config('modules.namespace', $this->path_namespace(config('modules.paths.modules'))) . '\\' . ($module);
$module_namespace .= strlen($path) ? '\\' . $this->path_namespace($path) : '';
return $this->studly_namespace($module_namespace);
}
}