first commit

This commit is contained in:
Sampanna Rimal
2024-08-27 17:48:06 +05:45
commit 53c0140f58
10839 changed files with 1125847 additions and 0 deletions

View File

@ -0,0 +1,14 @@
; This file is for unithyng the coding style for different editors and IDEs.
root = true;
[*]
charset = utf_8
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false

View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
github: nwidart
github: dcblogdev

View File

@ -0,0 +1,33 @@
name: PHP Pipeline
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 2
matrix:
php-versions: ['8.2', '8.3']
name: PHP ${{ matrix.php-versions }}
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@master
with:
php-version: ${{ matrix.php-versions }}
coverage: xdebug
- name: Validate composer.json and composer.lock
run: composer validate
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
- name: Run test suite
run: composer run-script test

View File

@ -0,0 +1,51 @@
<?php
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
$rules = [
'@PSR12' => true,
// Concatenation should be used with at least one whitespace around.
'concat_space' => ['spacing' => 'one'],
// Unused use statements must be removed.
'ordered_imports' => true,
// Removes extra empty lines.
'no_extra_blank_lines' => true,
// An empty line feed should precede a return statement.
'blank_line_before_statement' => true,
// Unused use statements must be removed.
'no_unused_imports' => true,
// Remove trailing whitespace at the end of blank lines.
'no_whitespace_in_blank_line' => true,
// There MUST be one blank line after the namespace declaration.
'blank_line_after_namespace' => true,
// Each namespace use MUST go on its own line and there MUST be one blank line after the use statements block.
'single_line_after_imports' => true,
// Ensure there is no code on the same line as the PHP open tag and it is followed by a blankline.
'blank_line_after_opening_tag' => true,
// Remove duplicated semicolons.
'no_empty_statement' => true,
// PHP multi-line arrays should have a trailing comma.
'trailing_comma_in_multiline' => true,
// There should be no empty lines after class opening brace.
'no_blank_lines_after_class_opening' => true,
// There should not be blank lines between docblock and the documented element.
'no_blank_lines_after_phpdoc' => true,
// Phpdocs should start and end with content, excluding the very first and last line of the docblocks.
'phpdoc_trim' => true,
];
$finder = Finder::create()
->in(__DIR__)
->exclude([
'vendor',
'tests/Commands/__snapshots__',
])
->ignoreDotFiles(true)
->ignoreVCS(true);
return (new Config())
->setFinder($finder)
->setRules($rules)
->setRiskyAllowed(true)
->setUsingCache(true);

View File

@ -0,0 +1,830 @@
# Changelog
All Notable changes to `laravel-modules` will be documented in this file.
## Next
## 11.0.6 - 2024-04-21
- [@alissn](https://github.com/alissn) change package version to Pretty on php artisan about
- [@alissn](https://github.com/alissn) fix stubs composer for app_folder
- [@dcblogdev](https://github.com/dcblogdev) added make-service command
## 11.0.5 - 2024-04-17
## Changes
- [@alissn](https://github.com/alissn) check command has direction option, load module with 'priority'
## 11.0.4 - 2024-04-08
## Changes
- [@dcblogdev](https://github.com/dcblogdev) Updated config to use namespace and path for seeders and factories
- [@solomon-ochepa](https://github.com/solomon-ochepa) Updated vendor / author keys for config/.env
- [@enterprime](https://github.com/enterprime) Corrected factories to Factories and added cache options to ENV
## Added
- [@dcblogdev](https://github.com/dcblogdev) Added return type array definition
- [@dcblogdev](https://github.com/dcblogdev) Added test to confirm author details
## 11.0.3 - 2024-03-24
## Added
- [@enterprime](https://github.com/enterprime) Passing the values of vendor, author's name, and author's email in a line during module creation.
- [@enterprime](https://github.com/enterprime) control the author through the .env configuration file.
## 11.0.2 - 2024-03-24
## Fixed
- [@enterprime](https://github.com/enterprime) fixed module:migrate-rollback command
## 11.0.1 - 2024-03-23
## Added
- [@alissn](https://github.com/alissn) add RouteServiceProvider Configuration in Generator
- [@alissn](https://github.com/alissn) added Laravel Modules package version to command 'about'
- [@dcblogdev](https://github.com/dcblogdev) Added view:make command to generate views
## Changed
- [@alissn](https://github.com/alissn) Run command php-cs-fixer fix
- [@solomon-ochepa](https://github.com/solomon-ochepa) updated route-provider.stub to loose the optional namespace
## 11.0.0 - 2024-03-19
## Fixed
- [@Subtixx](https://github.com/subtixx) Fix Issue #1752 - Hardcoded string + undefined variable
- [@jaymeh](https://github.com/jaymeh) fix: Failed to load module script for static assets such as images
- [@alissn](https://github.com/alissn) Fixing failing tests
## Changed
- [@dcblogdev](https://github.com/dcblogdev) ensure class_exists for both Capital and lower case namespaces
- [@dcblogdev](https://github.com/dcblogdev) create database folders by default
- [@dcblogdev](https://github.com/dcblogdev) set route service provider to use blank namespace by default
- [@dcblogdev](https://github.com/dcblogdev) updated tests for compatability with PhpUnit 12
- [@dcblogdev](https://github.com/dcblogdev) added replacement placeholders in config for API stubs
- [@dcblogdev](https://github.com/dcblogdev) updated vite to rename placeholder with module name
- [@dcblogdev](https://github.com/dcblogdev) Added support for Laravel 11
- [@solomon-ochepa](https://github.com/solomon-ochepa) updated API route stub to use controller
- [@solomon-ochepa](https://github.com/solomon-ochepa) updated config comments
- [@alissn](https://github.com/alissn) rearrange Command Classes into Folders and Update Namespace Structure
- [@alissn](https://github.com/alissn) delete command module:migrate-fresh
- [@alissn](https://github.com/alissn) Fixing Case of tests/Unit and tests/Feature
- [@alissn](https://github.com/alissn) Updated commands to use Laravel Prompt
- [@dcblogdev](https://github.com/dcblogdev) updated event stub to include Dispatchable and InteractsWithSockets traits
## 10.0.6 - 2024-01-28
## Added
- [@alissn](https://github.com/alissn) Add command module prune
## 10.0.5 - 2024-01-22
## Added
- [@azim-kordpour](https://github.com/azim-kordpour) Add PHPDoc static to all methods in Module facade
## Changed
- [@dcblogdev](https://github.com/dcblogdev) Reverted config to use `App` and `Database` namespace / folders by default
- [@alissn](https://github.com/alissn) Command Synchronization and Alphabetical Sorting in ConsoleServiceProvider
- [@fpermana](https://github.com/fpermana) Update ObserverMakeCommand.php
## Fixed
- [@alissn](https://github.com/alissn) revert extend class to ShowModelCommand
- [@benjaminniess](https://github.com/benjaminniess) Fix ModelShowCommand extends property
## 10.0.4 - 2023-11-13
## Changed
- [@dcblogdev](https://github.com/dcblogdev) updated module:publish-config to a dynamic path to the service provider
## 10.0.3 - 2023-10-02
## Changed
- [@solomon-ochepa](https://github.com/solomon-ochepa) updated multiple & config stubs to follow modern laravel standards
- [@dcblogdev](https://github.com/dcblogdev) updated enabled `$MODULE_NAMESPACE$` & `$CONTROLLER_NAMESPACE$` placeholders to be used inside stubs
- [@hungthai1401](https://github.com/hungthai1401) updated rule stub
## Added
- [@dcblogdev](https://github.com/dcblogdev) added support for using modules inside the main `vite.config.js` file https://github.com/nWidart/laravel-modules/pull/1682
- [@dcblogdev](https://github.com/dcblogdev) added option to generate a factory by using the flag `-f` when generating a model
- [@hungthai1401](https://github.com/hungthai1401 ) added implicit rule https://github.com/nWidart/laravel-modules/pull/1664
## 10.0.2 - 2023-09-18
## Changed
- reordered config commands and added missing observer command
## 10.0.1 - 2023-09-18
## Added
- [@JaberWiki](https://github.com/JaberWiki) Added Include an optional flag `subpath` for rolling back a module's specific migration file [#1626](https://github.com/nWidart/laravel-modules/pull/1626)
- [@sergiy-petrov](https://github.com/sergiy-petrov) Added support for testing GitHub actions against PHP versions 8.2 and 8.3. [#1624](https://github.com/nWidart/laravel-modules/pull/1624)
- [@hanieas](https://github.com/hanieas) Added make Observer command. [#1623](https://github.com/nWidart/laravel-modules/pull/1623)
- [@alissn](https://github.com/alissn) Add phpdoc to Module facade class for IDE auto-completion. [#1589](https://github.com/nWidart/laravel-modules/pull/1589)
- [@aryala7](https://github.com/aryala7) Add command to create broadcasting channel [#1599](https://github.com/nWidart/laravel-modules/pull/1599)
## Changed
- [@Rattone](https://github.com/Rattone) Updated stubs for command from `name` to `signature` [#1625](https://github.com/nWidart/laravel-modules/pull/1625)
- [@moeen-basra](https://github.com/moeen-basra) Remove the unused Factory import [#1596](https://github.com/nWidart/laravel-modules/pull/1596)
- [@moeen-basra](https://github.com/moeen-basra) Replace the \Config::get with config function [#1596](https://github.com/nWidart/laravel-modules/pull/1596)
- [@aryala7](https://github.com/aryala7) Changed disable module Command to accept array of modules instead of single module to disable [#1591](https://github.com/nWidart/laravel-modules/pull/1591)
## 10.0.0 - 2023-02-14
### Changed
- Minimum PHP version to 8.1 for supporting Laravel 10
- Laravel 10 version
- Increased PHPUnit to 10.0
- Increased Mockery to 1.5
## Updated
- [@dev-karpenko](https://github.com/dev-karpenko) updated get attributes cache [#1526](https://github.com/nWidart/laravel-modules/pull/1526)
## 9.0.7 - 2022-11-17
## Added
- [@alissn](https://github.com/alissn) implement command check lang folder, and show missing files [#1496](https://github.com/nWidart/laravel-modules/pull/1496)
- [@kmizzi](https://github.com/kmizzi) Use AsCommand in lieu of defaultName for ModelShowCommand [#1503](https://github.com/nWidart/laravel-modules/pull/1503)
## 9.0.6 - 2022-10-28
## Added
- [@wikigods](https://github.com/wikigods) added vite compatibility [#1455](https://github.com/nWidart/laravel-modules/pull/1455)
- [@WMOH-DEV](https://github.com/WMOH-DEV) Adding migrate fresh command [#1483](https://github.com/nWidart/laravel-modules/pull/1483)
## 9.0.5 - 2022-08-31
## Added
- [@alissn](https://github.com/alissn) add command show model information [#1429](https://github.com/nWidart/laravel-modules/pull/1429)
- [@JaberWiki](https://github.com/JaberWiki) add optional flag for seeder or request in model generator command [#1431](https://github.com/nWidart/laravel-modules/pull/1431)
## Changed
- [@alissn](https://github.com/alissn) updated command style to new version of artisan [#1430](https://github.com/nWidart/laravel-modules/pull/1430)
- [@ChauDucGiang](https://github.com/ChauDucGiang) updated Feature/cache driver [#1443](https://github.com/nWidart/laravel-modules/pull/1443)
### Fixed
- [@ajayfroiden](https://github.com/alissn) fixed module:disable [#1438](https://github.com/nWidart/laravel-modules/pull/1438)
- [@inovar-tecnologia](https://github.com/inovar-tecnologia) fixed DisableCommand.php[#1435](https://github.com/nWidart/laravel-modules/pull/1435)
## 9.0.4 - 2022-07-28
- 9.02 - 9.0.3 have been removed due to savere performance problems
## 9.0.1 - 2022-02-28
### Added
- Added option to publish stubs for modules `php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider" --tag="stubs"`
### Changed
- [@iamine](https://github.com/iamine) Added Anonymous migration class as default like in Laravel 9.0 [#1363](https://github.com/nWidart/laravel-modules/pull/1363)
## 9.0 - 2022-02-10
### Changed
- Minimum PHP version to 8.0 for supporting Laravel 9
- Laravel 9 version
- Increased PHPUnit to 9.5
- Increased Mockery to 1.4
- Fixed test replaced expectsEvents with event fakes
## 8.3 - 2022-02-10
### Fixed
- The ability to override commands via config file.
- Incorrectly placed config key
- Class name when special characters are used in the rule name
- Fix error on anonymous migration
### Changed
- Changed `View/Component` to `View/Components`
- Updated test snapshots for the MakeCommand test snapshots
- Command stub signature from `signature` to `name`
- Revert PR1171 which causes tests to fail
### Added
- Added commands make class component and make view component
- Test against php 8.0
- Merge config in register method
- Added optional controller flag to model generator command
- Set module for make-controller command
- Added tests for generating controller in model generator command
- Added test for check if migration and controller flag are both present
- Laravel mix v6 support
## 8.2 - 2020-11-11
### Added
- New `module:make-component` command to generate laravel components
### Fixed
- Fixed bug: `Target class [Nwidart\Modules\Commands\] does not exist.`
## 8.1 - 2020-11-10
### Added
- Command management via configuration file
- Laravel 8 Factories compatibility
- New improved way to define controller types. `--web`, `--api` and `--plain` options.
- New configuration option to make compose run in silent mode
### Changed
- New generated commands now use the `$signature` property instead of `$name`
- Fixed issue where `order` was used instead of `priority`
## 8.0 - 2020-10-03
### Added
- Laravel 8 support
### Updated
- Update `ListenerMakeCommand` to properly use the `--events` option
## 7.2.0 - 2020-07-30
### Added
- Added return statements in artisan commands. Helpful to validate if something was successfully ran. (#1026)
### Changed
- Update JsonResource namespace, using the new `Illuminate\Http\Resources\Json\JsonResource`. (#969)
- Enable command returns the status code (#978)
- Removing module service provider from composer.json stub (#996)
- Fixed custom stub path issue. Replacing a hardcoded stub path. (#1016)
- Controller return type changed to `Illuminate\Contracts\Support\Renderable`. (#1020)
- Change bigIncrements method to id (#1029)
- Adding force option for module:seed (#1030)
## 7.1.0 - 2020-04-14
### Changed
- `php artsian module:enable` (without any arguments) will enable all modules
- `php artsian module:disable` (without any arguments) will disable all modules
- Updating Laravel Mix version as well as cross-env.
## 7.0.0 - 2020-03-26
### Added
- Laravel 7.0 support
## 6.2.0 - 2019-11-12
### Changed
- Properly guessing the namespace from the path (in `GeneratorPath` class)
- Fixing generation of resource file if the resource has been disabled to generate
- Fix when using a custom service provider namespace, namespace is correctly referenced in module.json and compose.json
- Fix when using custom service provider namespace, module path is correctly referenced in the `RouteServiceProvider` and `ModuleServiceProvider`
- Fix when using a custom path for controllers in the controller stub
## 6.1.0 - 2019-11-01
### Added
- Added new `module:delete` command
### Changed
- Add optional path parameter to `module_path` helper (PR#861)
- The default path of the `module_statuses.json` file has been moved to the Application's base path. This is to improve its visibility and the fact that it can be committed by default.
- Throw an exception when no proper activator class was configured
## 6.0.0 - 2019-09-19
### Added
- New File Activator feature. [PR #790](https://github.com/nWidart/laravel-modules/pull/790) from @ryssbowh
This feature changes how modules are activated and de-activated. Currently module statuses are stored on disk, this features adds the possibility of storing this status information in a database.
**Use the command `php artisan module:v6:migrate` to have old modules active status migrated to the new system.**
### Changed
- Alternate way to define the namespace of modules in [PR #776](https://github.com/nWidart/laravel-modules/pull/776) by @daison12006013
This allows to have the content of the module under an `src/` folder for example.
- **BREAKING** New way to handle active and inactive modules.
Modules don't store their active status in their module.json file anymore, but in a file under the storage folder.
Run `php artisan module:v6:migrate` to use the new system.
- **BREAKING** Renamed method `enabled` to `isEnabled` in `\Nwidart\Modules\Module`.
- **BREAKING** Renamed method `disabled` to `isDisabled` in `\Nwidart\Modules\Module`.
- **BREAKING** Renamed method `enabled` to `isEnabled` in `\Nwidart\Modules\FileRepository`.
- **BREAKING** Renamed method `disabled` to `isDisabled` in `\Nwidart\Modules\FileRepository`.
- **BREAKING** Removed the `__get` magic method on the `\Nwidart\Modules\Module` class. Use `get()` or `json()->get()` instead.
- The `module:make-listener` command now correctly uses the namespace configuration
- The generated Factories now has type hints for the `\Illuminate\Database\Eloquent\Factory` class
- Improved foreign key constraint generation
- Exception handling in the `SeedCommand` has been improved
## 5.0.1 - 2019-05-11
### Added
- `artisan module:route-provider` has a `--force` option to overwrite existing file
### Changed
- Fixing the `RouteServiceProvider` generation to properly use the `routes/web` and `routes/api` stubs
- Replacing `@stop` with `@endsection` in the view stub file
- `Module` class does not extend Laravel's Service Provider class anymore
## 5.0.0 - 2019-03-18
### Added
- Laravel 5.8 support
### Changed
- Deprecated string and array methods have been replaced
- Fixed caching not being cleared after disabling and enabling modules
- Update Route Provider stub to not affect the root namespace of the URL generator (#727)
### Removed
- **PHP 7.1 support**
## 4.1.0 - 2019-03-04
### Changed
- Updated to laravel mix 4
- Add `--api` argument to `module:make-controller` command
- Seeding modules outside out `Modules` namespace
## 4.0.0 - 2018-09-30
### Added
- New way of handling routes by default using a RouteServiceProvider (instead of start.php)
- Laravel 5.7 support
### Changed
- Allow class resolution on short name and abstract
- `module:seed` accepts a `--class` option
## 3.3.1 - 2018-07-13
### Changed
- Added the ability to set a sub-namespace to controllers `module:make-controller Api\\TestController`
## 3.3.0 - 2018-06-21
### Changed
- `module:update` command has now the possibility to update all modules at once
- Fixing commented code for Laravel Mix
## 3.2.0 - 2018-04-16
### Added
- Added possibility to update all modules at once if any not specified (PR #523)
### Changed
- Mix: Fix css relative urls by changing the route folder (PR #521)
- Mix: Prevents every build from deleting previous Mix config file (PR #521)
## 3.1.0 - 2018-04-01
### Added
- Laravel mix configuration (https://nwidart.com/laravel-modules/v3/basic-usage/compiling-assets)
### Changed
- Allow symlinks in module path
- Returns the parameter `--class` to the `SeedCommand`.
- Generate folders recursively
- Removing link that has become a 404
- Fixed seed command exception typehint
### Removed
- Removed the optimize command on the `module:make-migration` command
## 3.0.1 - 2018-02-16
### Changed
- Update publish commands to use the new API to get all enabled modules (PR #483 )
## 3.0.0 - 2018-02-14
## Added
- Added support for laravel 5.6
- Using phpunit 7
## Changed
- **BC:** `Repository` class: renamed `enabled` to `allEnabled`
- **BC:** `Repository` class: renamed `disabled` to `allDisabled`
- **BC:** `Repository` class: renamed `active` to `enabled`
- **BC:** `Repository` class: renamed `notActive` to `disabled`
## Removed
- Dropped php 7.0 support
- **BC:** `Module` class: Deprecated `active()` method, use `enabled()`
- **BC:** `Module` class: Deprecated `notActive()` method, use `disabled()`
- **BC:** `Repository` class: Deprecated `addPath()` method, use `addLocation()`
- **BC:** `Repository` class: Deprecated `get()` method, use `find()`
- **BC:** `Repository` class: Deprecated `getUsed()` method, use `getUsedNow()`
## 2.7.0 - 2018-01-13
## Changed
- Rename the `before` method to `boot` in the `RouterServiceProvider` stub file
- Fixing caching issue if modules were loaded from a different directory
- Fixing how modules are loaded from vendor directory (#423 #417)
- Update to Mockery 1.0
- use default file stubs only if override does not exists
- Fix non well formed numeric value in seed command
## 2.6.0 - 2017-11-07
## Added
- Ability to customise the destination folder & namespace of a generated class
- Added `php artisan module:migrate-status` command
- `config_path()` helper for Lumen
- Added views tag to view config in ServiceProvider
- added package auto discovery for laravel 5.5 in generated module `composer.json`
## Changed
- Adding the ability to correctly load modules from multiple locations, together
- Custom seeder path now also used in the `module:seed` command
## 2.5.1 - 2017-10-13
## Changed
- added config_path helper to helpers for Lumen support
- updated readme on how to install laravel-modules in Lumen
## 2.5.0 - 2017-10-03
## Changed
- Making the path to migrations for `loadMigrationsFrom()` call dynamic based of configuration
- Making the factory path dynamic for master service provider & make-factory command
- Make the route file location dynamic in start.php based of `stubs.files.routes`
- Making the route path dynamic on the route service provider based of `stubs.files.routes`
- New structure in configuration to set which folders will be generated on `module:make` (old format still supported)
- Setting new sensible defaults to what folders to generate by default.
- Change the assets directory default location `resources/assets`
## 2.4.1 - 2017-09-27
## Changed
- Setting a default value for `modules.paths.modules` configuration key
## 2.4.0 - 2017-09-27
## Added
- New `module:make-resource` command to generate resource classes
- New `module:make-test` command to generate test classes
## Changed
- Improved error output of the `module:seed` command
- Marking methods that served as proxies in `Module` and `Repository` classes as deprecated for next major
- Fixed `module:make` and `module:make-provider` to generate the correct master service provider
- Tests: tests are now using `spatie/phpunit-snapshot-assertions` to make sure the generated files have the correct content
- Adding a sync option to the `module:make-job` command to make a synchronous job class
- Changed `module:make-event` command to allow duck typed events (not type hinted event class)
- Changed `module:make-listener` to allow a `--queued` option to make the event queueable
- Changed `module:make-listener` command to not use the full class typehint when class was previous imported
## 2.3.0 - 2017-09-26
## Added
- Ability to ignore some folders to generate
- Creating an module:unuse command to forget the previously saved module
- New command to generate Policy classes
- New command for creating factories
- New command for creating rules
- new `public_path` helper for Lumen
## Changed
- Refactored class names that generate something to be fully consistent
## 2.2.1 - 2017-09-14
## Changed
- Fixed class namespace to `Repository` in `ContractsServiceProvider`
## 2.2.0 - 2017-09-14
### Added
- Lumen compatibility with new way to register providers
## 2.1.0 - 2017-09-10
### Changed
- Register module migrations
- Fixed issue with `module:migrate-refresh` command
- Improved module loading of their service providers. Using laravel caching system. Allowing usage of deferred providers.
- Fixed path to module factories
## 2.0.0 - 2017-08-31
### Added
- Support Laravel 5.5
## 1.27.2 - 2017-08-29
### Changed
- Allow migrate-refresh command to be run without module argument
- Module name was added to the module enable and disable events
## 1.27.1 - 2017-07-31
### Changed
- Only run composer require on the module:update command if there's something to require
- Fixing lumen support
## 1.27.0 - 2017-07-19
### Added
- Laravel Lumen support
### Changed
- Update dev dependencies grumphp and phpcsfixer to latest versions
- The `make:model` command with the `-m` flag to create the associated migration is now using a current migration file name
## 1.26.0 - 2017-07-06
### Changed
- Throw an exception if asset name structure was not correct when using `{!! Module::asset() !!}`
- Create the module used file if non existent. Will provide for a better error message if module is omitted in console commands without a module:use.
## 1.25.1 - 2017-06-29
### Changed
- More flexibility to the `json()` method, while keeping the performance improvements.
## 1.25.0 - 2017-06-29
### Changed
- Improving performance by only instantiating Json class for the module.json file once
- Added support for generic git hosts
## 1.24.0 - 2017-06-12
### Changed
- Using `resource_path` to register module views
- Changed the method to load additional eloquent factory paths
## 1.23.0 - 2017-06-09
## Added
- A `--migration` flag to the `module:make-model` command to generate the migration file with a model
- Factories are now also defined in the master service providers. This is used in the `module:make` command without the `--plain` flag, or using `module:make-provider` with the `--master` flag.
- `module_path()` helper function.
### Changed
- The default location of event listeners is now in `Listeners/`, from `Events/Handlers`
## 1.22.0 - 2017-05-22
### Changed
- Fixed the `--plain` on the `make:module` command, to not include a service provider in the `module.json` file as it's not generated.
- Add command description to the `GenerateNotificationCommand`.
## 1.21.0 - 2017-05-10
### Added
- Added the `Macroable` trait to the `Module` class.
### Changed
- The `collections` method now accepts an optional parameter to get modules by status, in a laravel collection.
- Allow laravel `5.5.*` to be used.
## 1.20.0 - 2017-04-19
### Changed
- `module:update`: Copy over the scripts key to main composer.json file
- Add a `--subpath` option to migrate command
- `module:update`: Install / require all require & require-dev package at once, instead of multiple calls to composer require.
- `module:publish-config` command now uses the namespace set up in the configuration file.
## 1.19.0 - 2017-03-16
### Changed
- `module:update` command now also takes the `require-dev` key into account
- Making the `$migrations` parameter optional on `getLastBatchNumber()`
## 1.18.0 - 2017-03-13
### Changed
- The module list command (`module:list`) now returns the native module name
## 1.17.1 - 2017-03-02
### Changed
- Fixed issues with route file location in `start.php`
## 1.17.0 - 2017-02-27
### Changed
- Add checking for failure to parse module JSON
## 1.16.0 - 2017-01-24
### Added
- Support for Laravel 5.4
- Adding show method on resource controller
- Added check for cached routes to not load them multiple times
## 1.15.0 - 2017-01-12
### Added
- Module requirements (PR #117)
- Added `Macroable` trait to `Module` class (PR #116)
### Changed
- Added missing import of the `Schema` facade on migration stubs
- A default plain migration will be used if the name was not matched against a predefined structure (create, add, delete and drop)
- Add tests for all the different migration structures above
- Fix: respecting order in reverse migrations (PR #98)
- Fix: `module:reset` and `module:migrate-rollback` didn't have `--database` option (PR #88)
- Fix: `Module::asset()`, removed obsolete backslash. (PR #91)
## 1.14.0 - 2016-10-19
### Added
- `module:make-notification` command to generate a notification class
### Changed
- Usage of the `lists()` method on the laravel collection has been removed in favor of `pluck()`
- Modules can now overwrite the default migration and seed paths in the `module.json` file
## 0.13.1 - 2016-09-09
### Changed
- Generated emails are now generated in the `Emails` folder by default
## 0.13.0 - 2016-09-08
### Changed
- Ability to set default value on the config() method of a module.
- Mail: Setting default value to config. Using that as the namespace.
- Using PSR2 for generated stubs
## 0.12.0 - 2016-09-08
### Added
- Generation of Mailable classes
## 0.11.2 - 2016-08-29
### Changed
- Using stable version of laravelcollective/html (5.3)
## 0.11.1 - 2016-08-25
### Changed
- Using stable development of laravelcollective/html
## 0.11 - 2016-08-24
### Added
- Adding `module:make-job` command to generate a job class
- Adding support for Laravel 5.3
### Changed
- Added force option to module:seed command
## 0.10 - 2016-08-10
### Added
- Experimental Laravel 5.3 support
### Changed
- Make sure the class name has `Controller` appended to it as well. Previously only the file had it suffixed.
### Removed
- Dependencies: `pingpong/support` and `pingpong/generators`
## 0.9 - 2016-07-30
### Added
- Adding a plain option to the generate controller command
### Changed
- Generate controller command now generates all resource methods
## 0.8 - 2016-07-28
### Fixed
- Module generation namespace now works with `StudlyCase` ([Issue #14](https://github.com/nWidart/laravel-modules/issues/14))
- No module namespace fix (#13)
### Changed
- Using new service provider stub for module generation too
## 0.1 - 2016-06-27
Initial release

View File

@ -0,0 +1,23 @@
# The MIT License (MIT)
Copyright (c) 2014 Pingpong Labs
Copyright (c) 2016 Nicolas Widart bvba <n.widart@gmail.com>
> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.

View File

@ -0,0 +1,89 @@
# Laravel-Modules
[![Latest Version on Packagist](https://img.shields.io/packagist/v/nwidart/laravel-modules.svg?style=flat-square)](https://packagist.org/packages/nwidart/laravel-modules)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
[![Scrutinizer Coverage](https://img.shields.io/scrutinizer/coverage/g/nWidart/laravel-modules.svg?maxAge=86400&style=flat-square)](https://scrutinizer-ci.com/g/nWidart/laravel-modules/?branch=master)
[![Total Downloads](https://img.shields.io/packagist/dt/nwidart/laravel-modules.svg?style=flat-square)](https://packagist.org/packages/nwidart/laravel-modules)
| **Laravel** | **laravel-modules** |
|-------------|---------------------|
| 5.4 | ^1.0 |
| 5.5 | ^2.0 |
| 5.6 | ^3.0 |
| 5.7 | ^4.0 |
| 5.8 | ^5.0 |
| 6.0 | ^6.0 |
| 7.0 | ^7.0 |
| 8.0 | ^8.0 |
| 9.0 | ^9.0 |
| 10.0 | ^10.0 |
| 11.0 | ^11.0 |
`nwidart/laravel-modules` is a Laravel package created to manage your large Laravel app using modules. A Module is like a Laravel package, it has some views, controllers or models. This package is supported and tested in Laravel 11.
This package is a re-published, re-organised and maintained version of [pingpong/modules](https://github.com/pingpong-labs/modules), which isn't maintained anymore.
With one big bonus that the original package didn't have: **tests**.
## upgrade
To upgrade to version V11 follow [Upgrade Guide](https://laravelmodules.com/docs/v11/upgrade) on official document.
## Install
To install via Composer, run:
``` bash
composer require nwidart/laravel-modules
```
The package will automatically register a service provider and alias.
Optionally, publish the package's configuration file by running:
``` bash
php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"
```
### Autoloading
By default, the module classes are not loaded automatically. You can autoload your modules by adding merge-plugin to the extra section:
```json
"extra": {
"laravel": {
"dont-discover": []
},
"merge-plugin": {
"include": [
"Modules/*/composer.json"
]
}
},
```
**Tip: don't forget to run `composer dump-autoload` afterwards.**
## Documentation
You'll find installation instructions and full documentation on [https://laravelmodules.com/](https://laravelmodules.com/docs).
## Demo
You can see a demo using Laravel Breeze at https://github.com/laravel-modules-com/breeze-demo
This is a complete application using Auth, Base and Profile modules.
## Community
We also have a Discord community. [https://discord.gg/hkF7BRvRZK](https://discord.gg/hkF7BRvRZK) For quick help, ask questions in the appropriate channel.
## Credits
- [Nicolas Widart](https://github.com/nwidart)
- [David Carr](https://github.com/dcblogdev)
- [gravitano](https://github.com/gravitano)
- [All Contributors](../../contributors)
## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

View File

@ -0,0 +1,74 @@
{
"name": "nwidart/laravel-modules",
"description": "Laravel Module management",
"keywords": [
"modules",
"laravel",
"nwidart",
"module",
"rad"
],
"license": "MIT",
"authors": [
{
"name": "Nicolas Widart",
"email": "n.widart@gmail.com",
"homepage": "https://nicolaswidart.com",
"role": "Developer"
}
],
"require": {
"php": ">=8.2",
"ext-json": "*",
"wikimedia/composer-merge-plugin": "^2.1"
},
"require-dev": {
"phpunit/phpunit": "^11.0",
"mockery/mockery": "^1.6",
"orchestra/testbench": "^v9.0",
"friendsofphp/php-cs-fixer": "^v3.52",
"laravel/framework": "^v11.0",
"spatie/phpunit-snapshot-assertions": "^5.0",
"phpstan/phpstan": "^1.4"
},
"autoload": {
"psr-4": {
"Nwidart\\Modules\\": "src"
},
"files": [
"src/helpers.php"
]
},
"autoload-dev": {
"psr-4": {
"Nwidart\\Modules\\Tests\\": "tests",
"Modules\\Recipe\\": "tests/stubs/valid/Recipe"
}
},
"extra": {
"laravel": {
"providers": [
"Nwidart\\Modules\\LaravelModulesServiceProvider"
],
"aliases": {
"Module": "Nwidart\\Modules\\Facades\\Module"
}
},
"branch-alias": {
"dev-master": "11.0-dev"
}
},
"config": {
"allow-plugins": {
"wikimedia/composer-merge-plugin": true
}
},
"scripts": {
"update-snapshots": "./vendor/bin/phpunit --no-coverage -d --update-snapshots",
"test": "vendor/bin/phpunit",
"test-coverage": "vendor/bin/phpunit --coverage-html coverage",
"pcf": "vendor/bin/php-cs-fixer fix --verbose"
},
"minimum-stability": "dev",
"prefer-stable": true
}

View File

@ -0,0 +1,258 @@
<?php
use Nwidart\Modules\Activators\FileActivator;
use Nwidart\Modules\Providers\ConsoleServiceProvider;
return [
/*
|--------------------------------------------------------------------------
| Module Namespace
|--------------------------------------------------------------------------
|
| Default module namespace.
|
*/
'namespace' => 'Modules',
/*
|--------------------------------------------------------------------------
| Module Stubs
|--------------------------------------------------------------------------
|
| Default module stubs.
|
*/
'stubs' => [
'enabled' => false,
'path' => base_path('vendor/nwidart/laravel-modules/src/Commands/stubs'),
'files' => [
'routes/web' => 'routes/web.php',
'routes/api' => 'routes/api.php',
'views/index' => 'resources/views/index.blade.php',
'views/master' => 'resources/views/layouts/master.blade.php',
'scaffold/config' => 'config/config.php',
'composer' => 'composer.json',
'assets/js/app' => 'resources/assets/js/app.js',
'assets/sass/app' => 'resources/assets/sass/app.scss',
'vite' => 'vite.config.js',
'package' => 'package.json',
],
'replacements' => [
'routes/web' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'CONTROLLER_NAMESPACE'],
'routes/api' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'CONTROLLER_NAMESPACE'],
'vite' => ['LOWER_NAME', 'STUDLY_NAME'],
'json' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE', 'PROVIDER_NAMESPACE'],
'views/index' => ['LOWER_NAME'],
'views/master' => ['LOWER_NAME', 'STUDLY_NAME'],
'scaffold/config' => ['STUDLY_NAME'],
'composer' => [
'LOWER_NAME',
'STUDLY_NAME',
'VENDOR',
'AUTHOR_NAME',
'AUTHOR_EMAIL',
'MODULE_NAMESPACE',
'PROVIDER_NAMESPACE',
'APP_FOLDER_NAME',
],
],
'gitkeep' => true,
],
'paths' => [
/*
|--------------------------------------------------------------------------
| Modules path
|--------------------------------------------------------------------------
|
| This path is used to save the generated module.
| This path will also be added automatically to the list of scanned folders.
|
*/
'modules' => base_path('Modules'),
/*
|--------------------------------------------------------------------------
| Modules assets path
|--------------------------------------------------------------------------
|
| Here you may update the modules' assets path.
|
*/
'assets' => public_path('modules'),
/*
|--------------------------------------------------------------------------
| The migrations' path
|--------------------------------------------------------------------------
|
| Where you run the 'module:publish-migration' command, where do you publish the
| the migration files?
|
*/
'migration' => base_path('database/migrations'),
/*
|--------------------------------------------------------------------------
| The app path
|--------------------------------------------------------------------------
|
| app folder name
| for example can change it to 'src' or 'App'
*/
'app_folder' => 'app/',
/*
|--------------------------------------------------------------------------
| Generator path
|--------------------------------------------------------------------------
| Customise the paths where the folders will be generated.
| Setting the generate key to false will not generate that folder
*/
'generator' => [
// app/
'channels' => ['path' => 'app/Broadcasting', 'generate' => false],
'command' => ['path' => 'app/Console', 'generate' => false],
'emails' => ['path' => 'app/Emails', 'generate' => false],
'event' => ['path' => 'app/Events', 'generate' => false],
'jobs' => ['path' => 'app/Jobs', '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],
'rules' => ['path' => 'app/Rules', 'generate' => false],
'component-class' => ['path' => 'app/View/Components', 'generate' => false],
'service' => ['path' => 'app/Services', 'generate' => false],
// app/Http/
'controller' => ['path' => 'app/Http/Controllers', 'generate' => true],
'filter' => ['path' => 'app/Http/Middleware', 'generate' => false],
'request' => ['path' => 'app/Http/Requests', 'generate' => false],
// config/
'config' => ['path' => 'config', 'generate' => true],
// database/
'migration' => ['path' => 'database/migrations', 'generate' => true],
'seeder' => ['path' => 'database/seeders', 'namespace' => 'Database\Seeders', 'generate' => true],
'factory' => ['path' => 'database/factories', 'namespace' => 'Database\Factories', '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],
// routes/
'routes' => ['path' => 'routes', 'generate' => true],
// tests/
'test-unit' => ['path' => 'tests/Unit', 'generate' => true],
'test-feature' => ['path' => 'tests/Feature', 'generate' => true],
],
],
/*
|--------------------------------------------------------------------------
| Package commands
|--------------------------------------------------------------------------
|
| Here you can define which commands will be visible and used in your
| application. You can add your own commands to merge section.
|
*/
'commands' => ConsoleServiceProvider::defaultCommands()
->merge([
// New commands go here
])->toArray(),
/*
|--------------------------------------------------------------------------
| Scan Path
|--------------------------------------------------------------------------
|
| Here you define which folder will be scanned. By default will scan vendor
| directory. This is useful if you host the package in packagist website.
|
*/
'scan' => [
'enabled' => false,
'paths' => [
base_path('vendor/*/*'),
],
],
/*
|--------------------------------------------------------------------------
| Composer File Template
|--------------------------------------------------------------------------
|
| Here is the config for the composer.json file, generated by this package
|
*/
'composer' => [
'vendor' => env('MODULE_VENDOR', 'nwidart'),
'author' => [
'name' => env('MODULE_AUTHOR_NAME', 'Nicolas Widart'),
'email' => env('MODULE_AUTHOR_EMAIL', 'n.widart@gmail.com'),
],
'composer-output' => false,
],
/*
|--------------------------------------------------------------------------
| Caching
|--------------------------------------------------------------------------
|
| Here is the config for setting up the caching feature.
|
*/
'cache' => [
'enabled' => env('MODULES_CACHE_ENABLED', false),
'driver' => env('MODULES_CACHE_DRIVER', 'file'),
'key' => env('MODULES_CACHE_KEY', 'laravel-modules'),
'lifetime' => env('MODULES_CACHE_LIFETIME', 60),
],
/*
|--------------------------------------------------------------------------
| Choose what laravel-modules will register as custom namespaces.
| Setting one to false will require you to register that part
| in your own Service Provider class.
|--------------------------------------------------------------------------
*/
'register' => [
'translations' => true,
/**
* load files on boot or register method
*/
'files' => 'register',
],
/*
|--------------------------------------------------------------------------
| Activators
|--------------------------------------------------------------------------
|
| You can define new types of activators here, file, database, etc. The only
| required parameter is 'class'.
| The file activator will store the activation status in storage/installed_modules
*/
'activators' => [
'file' => [
'class' => FileActivator::class,
'statuses-file' => base_path('modules_statuses.json'),
'cache-key' => 'activator.installed',
'cache-lifetime' => 604800,
],
],
'activator' => 'file',
];

View File

@ -0,0 +1,45 @@
import fs from 'fs/promises';
import path from 'path';
async function collectModuleAssetsPaths(paths, modulesPath) {
modulesPath = path.join(__dirname, modulesPath);
const moduleStatusesPath = path.join(__dirname, 'modules_statuses.json');
try {
// Read module_statuses.json
const moduleStatusesContent = await fs.readFile(moduleStatusesPath, 'utf-8');
const moduleStatuses = JSON.parse(moduleStatusesContent);
// Read module directories
const moduleDirectories = await fs.readdir(modulesPath);
for (const moduleDir of moduleDirectories) {
if (moduleDir === '.DS_Store') {
// Skip .DS_Store directory
continue;
}
// 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()) {
// Import the module-specific Vite configuration
const moduleConfig = await import(viteConfigPath);
if (moduleConfig.paths && Array.isArray(moduleConfig.paths)) {
paths.push(...moduleConfig.paths);
}
}
}
}
} catch (error) {
console.error(`Error reading module statuses or module configurations: ${error}`);
}
return paths;
}
export default collectModuleAssetsPaths;

View File

@ -0,0 +1,210 @@
<?php
namespace Nwidart\Modules\Activators;
use Illuminate\Cache\CacheManager;
use Illuminate\Config\Repository as Config;
use Illuminate\Container\Container;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\Filesystem\Filesystem;
use Nwidart\Modules\Contracts\ActivatorInterface;
use Nwidart\Modules\Module;
class FileActivator implements ActivatorInterface
{
/**
* Laravel cache instance
*
* @var CacheManager
*/
private $cache;
/**
* Laravel Filesystem instance
*
* @var Filesystem
*/
private $files;
/**
* Laravel config instance
*
* @var Config
*/
private $config;
/**
* @var string
*/
private $cacheKey;
/**
* @var string
*/
private $cacheLifetime;
/**
* Array of modules activation statuses
*
* @var array
*/
private $modulesStatuses;
/**
* File used to store activation statuses
*
* @var string
*/
private $statusesFile;
public function __construct(Container $app)
{
$this->cache = $app['cache'];
$this->files = $app['files'];
$this->config = $app['config'];
$this->statusesFile = $this->config('statuses-file');
$this->cacheKey = $this->config('cache-key');
$this->cacheLifetime = $this->config('cache-lifetime');
$this->modulesStatuses = $this->getModulesStatuses();
}
/**
* Get the path of the file where statuses are stored
*
* @return string
*/
public function getStatusesFilePath(): string
{
return $this->statusesFile;
}
/**
* @inheritDoc
*/
public function reset(): void
{
if ($this->files->exists($this->statusesFile)) {
$this->files->delete($this->statusesFile);
}
$this->modulesStatuses = [];
$this->flushCache();
}
/**
* @inheritDoc
*/
public function enable(Module $module): void
{
$this->setActiveByName($module->getName(), true);
}
/**
* @inheritDoc
*/
public function disable(Module $module): void
{
$this->setActiveByName($module->getName(), false);
}
/**
* @inheritDoc
*/
public function hasStatus(Module $module, bool $status): bool
{
if (!isset($this->modulesStatuses[$module->getName()])) {
return $status === false;
}
return $this->modulesStatuses[$module->getName()] === $status;
}
/**
* @inheritDoc
*/
public function setActive(Module $module, bool $active): void
{
$this->setActiveByName($module->getName(), $active);
}
/**
* @inheritDoc
*/
public function setActiveByName(string $name, bool $status): void
{
$this->modulesStatuses[$name] = $status;
$this->writeJson();
$this->flushCache();
}
/**
* @inheritDoc
*/
public function delete(Module $module): void
{
if (!isset($this->modulesStatuses[$module->getName()])) {
return;
}
unset($this->modulesStatuses[$module->getName()]);
$this->writeJson();
$this->flushCache();
}
/**
* Writes the activation statuses in a file, as json
*/
private function writeJson(): void
{
$this->files->put($this->statusesFile, json_encode($this->modulesStatuses, JSON_PRETTY_PRINT));
}
/**
* Reads the json file that contains the activation statuses.
* @return array
* @throws FileNotFoundException
*/
private function readJson(): array
{
if (!$this->files->exists($this->statusesFile)) {
return [];
}
return json_decode($this->files->get($this->statusesFile), true);
}
/**
* Get modules statuses, either from the cache or from
* the json statuses file if the cache is disabled.
* @return array
* @throws FileNotFoundException
*/
private function getModulesStatuses(): array
{
if (!$this->config->get('modules.cache.enabled')) {
return $this->readJson();
}
return $this->cache->store($this->config->get('modules.cache.driver'))->remember($this->cacheKey, $this->cacheLifetime, function () {
return $this->readJson();
});
}
/**
* Reads a config parameter under the 'activators.file' key
*
* @param string $key
* @param $default
* @return mixed
*/
private function config(string $key, $default = null)
{
return $this->config->get('modules.activators.file.' . $key, $default);
}
/**
* Flushes the modules activation statuses cache
*/
private function flushCache(): void
{
$this->cache->store($this->config->get('modules.cache.driver'))->forget($this->cacheKey);
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Nwidart\Modules;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Collection as BaseCollection;
class Collection extends BaseCollection
{
/**
* Get items collections.
*
* @return array
*/
public function getItems()
{
return $this->items;
}
/**
* Get the collection of items as a plain array.
*
* @return array
*/
public function toArray()
{
return array_map(function ($value) {
if ($value instanceof Module) {
$attributes = $value->json()->getAttributes();
$attributes["path"] = $value->getPath();
return $attributes;
}
return $value instanceof Arrayable ? $value->toArray() : $value;
}, $this->items);
}
}

View File

@ -0,0 +1,202 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Illuminate\Support\Collection;
use Nwidart\Modules\Commands\BaseCommand;
class CheckLangCommand extends BaseCommand
{
private $langPath;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:lang';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Check missing language keys in the specified module.';
public function __construct()
{
parent::__construct();
$this->langPath = DIRECTORY_SEPARATOR . config('modules.paths.generator.lang.path', 'Resources/lang');
}
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$directories = $this->getDirectories($module);
if (! $directories) {
return;
}
$this->checkMissingFiles($directories);
$this->checkMissingKeys($directories);
}
public function getInfo(): string|null
{
return 'Checking languages ...';
}
private function getLangFiles($module)
{
$files = [];
$path = $module->getPath() . $this->langPath;
if (is_dir($path)) {
$files = array_merge($files, $this->laravel['files']->all($path));
}
return $files;
}
private function getDirectories($module)
{
$moduleName = $module->getStudlyName();
$path = $module->getPath() . $this->langPath;
$directories = [];
if (is_dir($path)) {
$directories = $this->laravel['files']->directories($path);
$directories = array_map(function ($directory) use ($moduleName) {
return [
'name' => basename($directory),
'module' => $moduleName,
'path' => $directory,
'files' => array_map(function ($file) {
return basename($file);
}, \File::glob($directory . DIRECTORY_SEPARATOR . "*")),
];
}, $directories);
}
if (count($directories) == 0) {
$this->components->info("No language files found in module $moduleName");
return false;
}
if (count($directories) == 1) {
$this->components->warn("Only one language file found in module $moduleName");
return false;
}
return collect($directories);
}
private function checkMissingFiles(Collection $directories)
{
//show missing files
$missingFilesMessage = [];
$uniqeLangFiles = $directories->pluck('files')->flatten()->unique()->values();
$directories->each(function ($directory) use ($uniqeLangFiles, &$missingFilesMessage) {
$missingFiles = $uniqeLangFiles->diff($directory['files']);
if ($missingFiles->count() > 0) {
$missingFiles->each(function ($missingFile) use ($directory, &$missingFilesMessage) {
$missingFilesMessage[$directory['name']][] = " {$directory['module']} - Missing language file: {$directory['name']}/{$missingFile}";
});
}
});
if (count($missingFilesMessage) > 0) {
collect($missingFilesMessage)->each(function ($messages, $langDirectory) {
$this->components->error("Missing language files in $langDirectory directory");
$this->components->bulletList(
collect($messages)->unique()->values()->toArray()
);
$this->newLine();
});
}
}
private function checkMissingKeys(Collection $directories)
{
//show missing keys
$uniqeLangFiles = $directories->pluck('files')->flatten()->unique();
$langDirectories = $directories->pluck('name');
$missingKeysMessage = [];
$directories->each(function ($directory) use ($uniqeLangFiles, $langDirectories, &$missingKeysMessage) {
$uniqeLangFiles->each(function ($file) use ($directory, $langDirectories, &$missingKeysMessage) {
$langKeys = $this->getLangKeys($directory['path'] . DIRECTORY_SEPARATOR . $file);
if ($langKeys == false) {
return;
}
$langDirectories->each(function ($langDirectory) use ($directory, $file, $langKeys, &$missingKeysMessage) {
if ($directory['name'] != $langDirectory) {
$basePath = str_replace($directory['name'], $langDirectory, $directory['path']);
$otherLangKeys = $this->getLangKeys($basePath . DIRECTORY_SEPARATOR . $file);
if ($otherLangKeys == false) {
return;
}
$missingKeys = $langKeys->diff($otherLangKeys);
if ($missingKeys->count() > 0) {
$missingKeys->each(function ($missingKey) use ($directory, $langDirectory, $file, &$missingKeysMessage) {
$missingKeysMessage[$langDirectory][] = " {$directory['module']} - Missing language key: {$langDirectory}/{$file} | key: $missingKey";
});
}
}
});
});
});
if (count($missingKeysMessage) > 0) {
collect($missingKeysMessage)->each(function ($messages, $langDirectory) {
$this->components->error("Missing language keys for directory $langDirectory:");
$this->components->bulletList(
collect($messages)->unique()->values()->toArray()
);
$this->newLine();
});
}
}
private function getLangKeys($file)
{
if (\File::exists($file)) {
$lang = \File::getRequire($file);
return collect(\Arr::dot($lang))->keys();
} else {
return false;
}
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Nwidart\Modules\Commands\BaseCommand;
class DisableCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:disable';
/**
* The console command signature.
*
* @var string
*/
protected $signature = 'module:disable';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Disable an array of modules.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$status = $module->isDisabled()
? '<fg=red;options=bold>Disabled</>'
: '<fg=green;options=bold>Enabled</>';
$this->components->task("Disabling <fg=cyan;options=bold>{$module->getName()}</> Module, old status: $status", function () use ($module) {
$module->disable();
});
}
public function getInfo(): string|null
{
return 'Disabling module ...';
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Nwidart\Modules\Commands\BaseCommand;
class DumpCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:dump';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Dump-autoload the specified module or for all module.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Generating for <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
chdir($module->getPath());
passthru('composer dump -o -n -q');
});
}
public function getInfo(): string|null
{
return 'Generating optimized autoload modules';
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Nwidart\Modules\Commands\BaseCommand;
class EnableCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:enable';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Enable the specified module.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$status = $module->isDisabled()
? '<fg=red;options=bold>Disabled</>'
: '<fg=green;options=bold>Enabled</>';
$this->components->task("Enabling <fg=cyan;options=bold>{$module->getName()}</> Module, old status: $status", function () use ($module) {
$module->enable();
});
}
public function getInfo(): string|null
{
return 'Disabling module ...';
}
}

View File

@ -0,0 +1,148 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Illuminate\Console\Command;
use Nwidart\Modules\Json;
use Nwidart\Modules\Process\Installer;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class InstallCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:install';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Install the specified module by given package name (vendor/name).';
/**
* Create a new command instance.
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle(): int
{
if (is_null($this->argument('name'))) {
return $this->installFromFile();
}
$this->install(
$this->argument('name'),
$this->argument('version'),
$this->option('type'),
$this->option('tree')
);
return 0;
}
/**
* Install modules from modules.json file.
*/
protected function installFromFile(): int
{
if (!file_exists($path = base_path('modules.json'))) {
$this->error("File 'modules.json' does not exist in your project root.");
return E_ERROR;
}
$modules = Json::make($path);
$dependencies = $modules->get('require', []);
foreach ($dependencies as $module) {
$module = collect($module);
$this->install(
$module->get('name'),
$module->get('version'),
$module->get('type')
);
}
return 0;
}
/**
* Install the specified module.
*
* @param string $name
* @param string $version
* @param string $type
* @param bool $tree
*/
protected function install($name, $version = 'dev-master', $type = 'composer', $tree = false)
{
$installer = new Installer(
$name,
$version,
$type ?: $this->option('type'),
$tree ?: $this->option('tree')
);
$installer->setRepository($this->laravel['modules']);
$installer->setConsole($this);
if ($timeout = $this->option('timeout')) {
$installer->setTimeout($timeout);
}
if ($path = $this->option('path')) {
$installer->setPath($path);
}
$installer->run();
if (!$this->option('no-update')) {
$this->call('module:update', [
'module' => $installer->getModuleName(),
]);
}
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::OPTIONAL, 'The name of module will be installed.'],
['version', InputArgument::OPTIONAL, 'The version of module will be installed.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['timeout', null, InputOption::VALUE_OPTIONAL, 'The process timeout.', null],
['path', null, InputOption::VALUE_OPTIONAL, 'The installation path.', null],
['type', null, InputOption::VALUE_OPTIONAL, 'The type of installation.', null],
['tree', null, InputOption::VALUE_NONE, 'Install the module as a git subtree', null],
['no-update', null, InputOption::VALUE_NONE, 'Disables the automatic update of the dependencies.', null],
];
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Illuminate\Console\Command;
use Nwidart\Modules\Module;
use Symfony\Component\Console\Input\InputOption;
class ListCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:list';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Show list of all modules.';
/**
* Execute the console command.
*/
public function handle(): int
{
$this->components->twoColumnDetail('<fg=gray>Status / Name</>', '<fg=gray>Path / priority</>');
collect($this->getRows())->each(function ($row) {
$this->components->twoColumnDetail("[{$row[1]}] {$row[0]}", "{$row[3]} [{$row[2]}]");
});
return 0;
}
/**
* Get table rows.
*
* @return array
*/
public function getRows()
{
$rows = [];
/** @var Module $module */
foreach ($this->getModules() as $module) {
$rows[] = [
$module->getName(),
$module->isEnabled() ? '<fg=green>Enabled</>' : '<fg=red>Disabled</>',
$module->get('priority'),
$module->getPath(),
];
}
return $rows;
}
public function getModules()
{
switch ($this->option('only')) {
case 'enabled':
return $this->laravel['modules']->getByStatus(1);
break;
case 'disabled':
return $this->laravel['modules']->getByStatus(0);
break;
case 'priority':
return $this->laravel['modules']->getPriority($this->option('direction'));
break;
default:
return $this->laravel['modules']->all();
break;
}
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['only', 'o', InputOption::VALUE_OPTIONAL, 'Types of modules will be displayed.', null],
['direction', 'd', InputOption::VALUE_OPTIONAL, 'The direction of ordering.', 'asc'],
];
}
}

View File

@ -0,0 +1,125 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Database\Console\PruneCommand;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use InvalidArgumentException;
use function Laravel\Prompts\multiselect;
use Nwidart\Modules\Facades\Module;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
class ModelPruneCommand extends PruneCommand implements PromptsForMissingInput
{
public const ALL = 'All';
protected $name = 'module:prune';
/**
* The console command name.
*
* @var string
*/
protected $signature = 'module:prune {module*}
{--all : Check all Modules}
{--model=* : Class names of the models to be pruned}
{--except=* : Class names of the models to be excluded from pruning}
{--path=* : Absolute path(s) to directories where models are located}
{--chunk=1000 : The number of models to retrieve per chunk of models to be deleted}
{--pretend : Display the number of prunable records found instead of deleting them}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Prune models by module that are no longer needed';
protected function promptForMissingArguments(InputInterface $input, OutputInterface $output): void
{
if ($this->option('all')) {
$input->setArgument('module', [self::ALL]);
return;
}
$selected_item = multiselect(
label : 'What Module want to check?',
options : [
self::ALL,
...array_keys(Module::all()),
],
required: 'You must select at least one module',
);
$input->setArgument(
'module',
value: in_array(self::ALL, $selected_item)
? [self::ALL]
: $selected_item
);
}
/**
* Determine the models that should be pruned.
*
* @return Collection
*/
protected function models(): Collection
{
if (! empty($models = $this->option('model'))) {
return collect($models)->filter(function ($model) {
return class_exists($model);
})->values();
}
$except = $this->option('except');
if (! empty($models) && ! empty($except)) {
throw new InvalidArgumentException('The --models and --except options cannot be combined.');
}
if ($this->argument('module') == [self::ALL]) {
$path = sprintf(
'%s/*/%s',
config('modules.paths.modules'),
config('modules.paths.generator.model.path')
);
} else {
$path = sprintf(
'%s/{%s}/%s',
config('modules.paths.modules'),
collect($this->argument('module'))->implode(','),
config('modules.paths.generator.model.path')
);
}
return collect(Finder::create()->in($path)->files()->name('*.php'))
->map(function ($model) {
$namespace = config('modules.namespace');
return $namespace . str_replace(
['/', '.php'],
['\\', ''],
Str::after($model->getRealPath(), realpath(config('modules.paths.modules')))
);
})->values()
->when(! empty($except), function ($models) use ($except) {
return $models->reject(function ($model) use ($except) {
return in_array($model, $except);
});
})->filter(function ($model) {
return class_exists($model);
})->filter(function ($model) {
return $this->isPrunable($model);
})->values();
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Illuminate\Database\Console\ShowModelCommand;
use Symfony\Component\Console\Attribute\AsCommand;
#[AsCommand('module:model-show', 'Show information about an Eloquent model in modules')]
class ModelShowCommand extends ShowModelCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:model-show';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Show information about an Eloquent model in modules';
/**
* The console command signature.
*
* @var string
*/
protected $signature = 'module:model-show {model : The model to show}
{--database= : The database connection to use}
{--json : Output the model as JSON}';
/**
* Qualify the given model class base name.
*
* @param string $model
* @return string
*
* @see \Illuminate\Console\GeneratorCommand
*/
protected function qualifyModel(string $model): string
{
if (str_contains($model, '\\') && class_exists($model)) {
return $model;
}
$rootNamespace = config('modules.namespace');
$modelPath = glob($rootNamespace . DIRECTORY_SEPARATOR .
'*' . DIRECTORY_SEPARATOR .
config('modules.paths.generator.model.path') . DIRECTORY_SEPARATOR .
"$model.php");
if (!count($modelPath)) {
return $model;
}
return str_replace(['/', '.php'], ['\\', ''], $modelPath[0]);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Nwidart\Modules\Commands\BaseCommand;
class ModuleDeleteCommand extends BaseCommand
{
protected $name = 'module:delete';
protected $description = 'Delete a module from the application';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Deleting <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
$module->delete();
});
}
public function getInfo(): string|null
{
return 'deleting module ...';
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Nwidart\Modules\Commands\BaseCommand;
class UnUseCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:unuse';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Forget the used module with module:use';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Forget Using <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
$this->laravel['modules']->forgetUsed($module);
});
}
public function getInfo(): string|null
{
return 'Forget Using Module ...';
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Nwidart\Modules\Commands\BaseCommand;
class UpdateCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:update';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Update dependencies for the specified module or for all modules.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Updating <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
$this->laravel['modules']->update($module);
});
}
public function getInfo(): string|null
{
return 'Updating Module ...';
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Nwidart\Modules\Commands\Actions;
use Nwidart\Modules\Commands\BaseCommand;
class UseCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:use';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Use the specified module.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Using <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
$this->laravel['modules']->setUsed($module);
});
}
public function getInfo(): string|null
{
return 'Using Module ...';
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace Nwidart\Modules\Commands;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use function Laravel\Prompts\multiselect;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
abstract class BaseCommand extends Command implements PromptsForMissingInput
{
public const ALL = 'All';
/**
* Create a new console command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
$this->getDefinition()->addOption(new InputOption(
strtolower(self::ALL),
'a',
InputOption::VALUE_NONE,
'Check all Modules',
));
$this->getDefinition()->addArgument(new InputArgument(
'module',
InputArgument::IS_ARRAY,
'The name of module will be used.',
));
}
abstract public function executeAction($name);
public function getInfo(): string|null
{
return null;
}
/**
* Execute the console command.
*/
public function handle()
{
if (! is_null($info = $this->getInfo())) {
$this->components->info($info);
}
$modules = (array) $this->argument('module');
foreach ($modules as $module) {
$this->executeAction($module);
}
}
protected function promptForMissingArguments(InputInterface $input, OutputInterface $output): void
{
$modules = $this->hasOption('direction')
? array_keys($this->laravel['modules']->getOrdered($input->hasOption('direction')))
: array_keys($this->laravel['modules']->all());
if ($input->getOption(strtolower(self::ALL))) {
$input->setArgument('module', $modules);
return;
}
if (! empty($input->getArgument('module'))) {
return;
}
$selected_item = multiselect(
label : 'What Module want to check?',
options : [
self::ALL,
...$modules,
],
required: 'You must select at least one module',
);
$input->setArgument(
'module',
value: in_array(self::ALL, $selected_item)
? $modules
: $selected_item
);
}
protected function getModuleModel($name)
{
return $name instanceof \Nwidart\Modules\Module
? $name
: $this->laravel['modules']->findOrFail($name);
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace Nwidart\Modules\Commands;
use Illuminate\Support\Facades\File;
class ComposerUpdateCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:composer-update';
/**
* The console command description.
*
* @var string
*/
protected $description = 'update autoload of composer.json file';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Updating Composer.json <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
$composer_path = $module->getPath() . DIRECTORY_SEPARATOR . 'composer.json';
$composer = json_decode(File::get($composer_path), true);
$autoload = data_get($composer, 'autoload.psr-4');
if (! $autoload) {
return;
}
$key_name_with_app = sprintf('Modules\\%s\\App\\', $module->getStudlyName());
if (! array_key_exists($key_name_with_app, $autoload)) {
return;
}
unset($autoload[$key_name_with_app]);
$key_name_with_out_app = sprintf('Modules\\%s\\', $module->getStudlyName());
$autoload[$key_name_with_out_app] = 'app/';
data_set($composer, 'autoload.psr-4', $autoload);
file_put_contents($composer_path, json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
});
}
public function getInfo(): string|null
{
return 'Updating Composer.json of modules...';
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace Nwidart\Modules\Commands\Database;
use Nwidart\Modules\Commands\BaseCommand;
use Nwidart\Modules\Migrations\Migrator;
use Symfony\Component\Console\Input\InputOption;
class MigrateCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:migrate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Migrate the migrations from the specified module or from all modules.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Running Migration <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
$path = str_replace(base_path(), '', (new Migrator($module, $this->getLaravel()))->getPath());
if ($this->option('subpath')) {
$path = $path . "/" . $this->option("subpath");
}
$this->call('migrate', [
'--path' => $path,
'--database' => $this->option('database'),
'--pretend' => $this->option('pretend'),
'--force' => $this->option('force'),
]);
if ($this->option('seed')) {
$this->call('module:seed', ['module' => $module->getName(), '--force' => $this->option('force')]);
}
});
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['direction', 'd', InputOption::VALUE_OPTIONAL, 'The direction of ordering.', 'asc'],
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run.'],
['subpath', null, InputOption::VALUE_OPTIONAL, 'Indicate a subpath to run your migrations from'],
];
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace Nwidart\Modules\Commands\Database;
use Nwidart\Modules\Commands\BaseCommand;
use Symfony\Component\Console\Input\InputOption;
class MigrateRefreshCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:migrate-refresh';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Rollback & re-migrate the modules migrations.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Refreshing Migration {$module->getName()} module", function () use ($module) {
$this->call('module:migrate-reset', [
'module' => $module->getStudlyName(),
'--database' => $this->option('database'),
'--force' => $this->option('force'),
]);
$this->call('module:migrate', [
'module' => $module->getStudlyName(),
'--database' => $this->option('database'),
'--force' => $this->option('force'),
]);
if ($this->option('seed')) {
$this->call('module:seed', [
'module' => $module->getStudlyName(),
]);
}
});
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run.'],
];
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace Nwidart\Modules\Commands\Database;
use Nwidart\Modules\Commands\BaseCommand;
use Nwidart\Modules\Migrations\Migrator;
use Nwidart\Modules\Traits\MigrationLoaderTrait;
use Symfony\Component\Console\Input\InputOption;
class MigrateResetCommand extends BaseCommand
{
use MigrationLoaderTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:migrate-reset';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Reset the modules migrations.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$migrator = new Migrator($module, $this->getLaravel());
$database = $this->option('database');
if (! empty($database)) {
$migrator->setDatabase($database);
}
$migrated = $migrator->reset();
if (count($migrated)) {
foreach ($migrated as $migration) {
$this->line("Rollback: <info>{$migration}</info>");
}
return;
}
$this->components->warn("Nothing to rollback on module <fg=cyan;options=bold>{$module->getName()}</>");
}
public function getInfo(): string|null
{
return null;
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['direction', 'd', InputOption::VALUE_OPTIONAL, 'The direction of ordering.', 'desc'],
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'],
];
}
}

View File

@ -0,0 +1,74 @@
<?php
namespace Nwidart\Modules\Commands\Database;
use Nwidart\Modules\Commands\BaseCommand;
use Nwidart\Modules\Migrations\Migrator;
use Nwidart\Modules\Traits\MigrationLoaderTrait;
use Symfony\Component\Console\Input\InputOption;
class MigrateRollbackCommand extends BaseCommand
{
use MigrationLoaderTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:migrate-rollback';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Rollback the modules migrations.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$migrator = new Migrator($module, $this->getLaravel(), $this->option('subpath'));
$database = $this->option('database');
if (! empty($database)) {
$migrator->setDatabase($database);
}
$migrated = $migrator->rollback();
if (count($migrated)) {
foreach ($migrated as $migration) {
$this->components->task("Rollback: <info>{$migration}</info>", );
}
return;
}
$this->components->warn("Nothing to rollback on module <fg=cyan;options=bold>{$module->getName()}</>");
}
public function getInfo(): string|null
{
return null;
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['direction', 'd', InputOption::VALUE_OPTIONAL, 'The direction of ordering.', 'desc'],
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'],
['subpath', null, InputOption::VALUE_OPTIONAL, 'Indicate a subpath for modules specific migration file'],
];
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Nwidart\Modules\Commands\Database;
use Nwidart\Modules\Commands\BaseCommand;
use Nwidart\Modules\Migrations\Migrator;
use Symfony\Component\Console\Input\InputOption;
class MigrateStatusCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:migrate-status';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Status for all module migrations';
/**
* @var \Nwidart\Modules\Contracts\RepositoryInterface
*/
protected $module;
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$path = str_replace(base_path(), '', (new Migrator($module, $this->getLaravel()))->getPath());
$this->call('migrate:status', [
'--path' => $path,
'--database' => $this->option('database'),
]);
}
public function getInfo(): string|null
{
return null;
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['direction', 'd', InputOption::VALUE_OPTIONAL, 'The direction of ordering.', 'asc'],
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
];
}
}

View File

@ -0,0 +1,234 @@
<?php
namespace Nwidart\Modules\Commands\Database;
use ErrorException;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Support\Str;
use Nwidart\Modules\Commands\BaseCommand;
use Nwidart\Modules\Contracts\RepositoryInterface;
use Nwidart\Modules\Module;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use RuntimeException;
use Symfony\Component\Console\Input\InputOption;
class SeedCommand extends BaseCommand
{
use ModuleCommandTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:seed';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Run database seeder from the specified module or from all modules.';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Seeding <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
try {
$this->moduleSeed($module);
} catch (\Error $e) {
$e = new ErrorException($e->getMessage(), $e->getCode(), 1, $e->getFile(), $e->getLine(), $e);
$this->reportException($e);
$this->renderException($this->getOutput(), $e);
return false;
} catch (\Exception $e) {
$this->reportException($e);
$this->renderException($this->getOutput(), $e);
return false;
}
});
}
public function getInfo(): string|null
{
return 'Seeding module ...';
}
/**
* @throws RuntimeException
* @return RepositoryInterface
*/
public function getModuleRepository(): RepositoryInterface
{
$modules = $this->laravel['modules'];
if (!$modules instanceof RepositoryInterface) {
throw new RuntimeException('Module repository not found!');
}
return $modules;
}
/**
* @param $name
*
* @throws RuntimeException
*
* @return Module
*/
public function getModuleByName($name)
{
$modules = $this->getModuleRepository();
if ($modules->has($name) === false) {
throw new RuntimeException("Module [$name] does not exists.");
}
return $modules->find($name);
}
/**
* @param Module $module
*
* @return void
*/
public function moduleSeed(Module $module)
{
$seeders = [];
$name = $module->getName();
$config = $module->get('migration');
if (is_array($config) && array_key_exists('seeds', $config)) {
foreach ((array)$config['seeds'] as $class) {
if (class_exists($class)) {
$seeders[] = $class;
}
}
} else {
$class = $this->getSeederName($name); //legacy support
$class = implode('\\', array_map('ucwords', explode('\\', $class)));
if (class_exists($class)) {
$seeders[] = $class;
} else {
//look at other namespaces
$classes = $this->getSeederNames($name);
foreach ($classes as $class) {
if (class_exists($class)) {
$seeders[] = $class;
}
}
}
}
if (count($seeders) > 0) {
array_walk($seeders, [$this, 'dbSeed']);
$this->info("Module [$name] seeded.");
}
}
/**
* Seed the specified module.
*
* @param string $className
*/
protected function dbSeed($className)
{
if ($option = $this->option('class')) {
$params['--class'] = Str::finish(substr($className, 0, strrpos($className, '\\')), '\\') . $option;
} else {
$params = ['--class' => $className];
}
if ($option = $this->option('database')) {
$params['--database'] = $option;
}
if ($option = $this->option('force')) {
$params['--force'] = $option;
}
$this->call('db:seed', $params);
}
/**
* Get master database seeder name for the specified module.
*
* @param string $name
*
* @return string
*/
public function getSeederName($name)
{
$name = Str::studly($name);
$namespace = $this->laravel['modules']->config('namespace');
$config = GenerateConfigReader::read('seeder');
$seederPath = str_replace('/', '\\', $config->getPath());
return $namespace . '\\' . $name . '\\' . $seederPath . '\\' . $name . 'DatabaseSeeder';
}
/**
* Get master database seeder name for the specified module under a different namespace than Modules.
*
* @param string $name
*
* @return array $foundModules array containing namespace paths
*/
public function getSeederNames($name)
{
$name = Str::studly($name);
$seederPath = GenerateConfigReader::read('seeder');
$seederPath = str_replace('/', '\\', $seederPath->getPath());
$foundModules = [];
foreach ($this->laravel['modules']->config('scan.paths') as $path) {
$namespace = array_slice(explode('/', $path), -1)[0];
$foundModules[] = $namespace . '\\' . $name . '\\' . $seederPath . '\\' . $name . 'DatabaseSeeder';
}
return $foundModules;
}
/**
* Report the exception to the exception handler.
*
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @param \Throwable $e
* @return void
*/
protected function renderException($output, \Exception $e)
{
$this->laravel[ExceptionHandler::class]->renderForConsole($output, $e);
}
/**
* Report the exception to the exception handler.
*
* @param \Throwable $e
* @return void
*/
protected function reportException(\Exception $e)
{
$this->laravel[ExceptionHandler::class]->report($e);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['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,39 @@
<?php
declare(strict_types=1);
namespace Nwidart\Modules\Commands;
use Illuminate\Console\Command;
use Nwidart\Modules\Contracts\RepositoryInterface;
use Nwidart\Modules\Module;
class LaravelModulesV6Migrator extends Command
{
protected $name = 'module:v6:migrate';
protected $description = 'Migrate laravel-modules v5 modules statuses to v6.';
public function handle(): int
{
$moduleStatuses = [];
/** @var RepositoryInterface $modules */
$modules = $this->laravel['modules'];
$modules = $modules->all();
/** @var Module $module */
foreach ($modules as $module) {
if ($module->json()->get('active') === 1) {
$module->enable();
$moduleStatuses[] = [$module->getName(), 'Enabled'];
}
if ($module->json()->get('active') === 0) {
$module->disable();
$moduleStatuses[] = [$module->getName(), 'Disabled'];
}
}
$this->info('All modules have been migrated.');
$this->table(['Module name', 'Status'], $moduleStatuses);
return 0;
}
}

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;
final class ChannelMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-channel';
protected $argumentName = 'name';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new channel class for the specified module.';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.channels.namespace')
?? ltrim(config('modules.paths.generator.channels.path', 'Broadcasting'), config('modules.paths.app_folder', ''));
}
/**
* Get template contents.
*
* @return string
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/channel.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* Get the destination file path.
*
* @return string
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$channelPath = GenerateConfigReader::read('channels');
return $path . $channelPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the channel class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
}

View File

@ -0,0 +1,109 @@
<?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 CommandMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate new Artisan command for the specified module.';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.command.namespace')
?? ltrim(config('modules.paths.generator.command.path', 'Console'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the command.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['command', null, InputOption::VALUE_OPTIONAL, 'The terminal command that should be assigned.', null],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/command.stub', [
'COMMAND_NAME' => $this->getCommandName(),
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* @return string
*/
private function getCommandName()
{
return $this->option('command') ?: 'command:name';
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$commandPath = GenerateConfigReader::read('command');
return $path . $commandPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
}

View File

@ -0,0 +1,106 @@
<?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;
class ComponentClassMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-component';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new component-class for the specified module.';
public function handle(): int
{
if (parent::handle() === E_ERROR) {
return E_ERROR;
}
$this->writeComponentViewTemplate();
return 0;
}
/**
* Write the view template for the component.
*
* @return void
*/
protected function writeComponentViewTemplate()
{
$this->call('module:make-component-view', ['name' => $this->argument('name') , 'module' => $this->argument('module')]);
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.component-class.namespace')
?? ltrim(config('modules.paths.generator.component-class.path', 'View/Component'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the component.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/component-class.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
'LOWER_NAME' => $module->getLowerName(),
'COMPONENT_NAME' => 'components.' . Str::lower($this->argument('name')),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$factoryPath = GenerateConfigReader::read('component-class');
return $path . $factoryPath->getPath() . '/' . $this->getFileName();
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name')) . '.php';
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Foundation\Inspiring;
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;
class ComponentViewMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-component-view';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new component-view for the specified module.';
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the component.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
return (new Stub('/component-view.stub', ['QUOTE' => Inspiring::quote()]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$factoryPath = GenerateConfigReader::read('component-view');
return $path . $factoryPath->getPath() . '/' . $this->getFileName();
}
/**
* @return string
*/
private function getFileName()
{
return Str::lower($this->argument('name')) . '.blade.php';
}
}

View File

@ -0,0 +1,140 @@
<?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 ControllerMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument being used.
*
* @var string
*/
protected $argumentName = 'controller';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-controller';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate new restful controller for the specified module.';
/**
* Get controller name.
*
* @return string
*/
public function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$controllerPath = GenerateConfigReader::read('controller');
return $path . $controllerPath->getPath() . '/' . $this->getControllerName() . '.php';
}
/**
* @return string
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'MODULENAME' => $module->getStudlyName(),
'CONTROLLERNAME' => $this->getControllerName(),
'NAMESPACE' => $module->getStudlyName(),
'CLASS_NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getControllerNameWithoutNamespace(),
'LOWER_NAME' => $module->getLowerName(),
'MODULE' => $this->getModuleName(),
'NAME' => $this->getModuleName(),
'STUDLY_NAME' => $module->getStudlyName(),
'MODULE_NAMESPACE' => $this->laravel['modules']->config('namespace'),
]))->render();
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['controller', InputArgument::REQUIRED, 'The name of the controller class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return array
*/
protected function getOptions()
{
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.'],
];
}
/**
* @return array|string
*/
protected function getControllerName()
{
$controller = Str::studly($this->argument('controller'));
if (Str::contains(strtolower($controller), 'controller') === false) {
$controller .= 'Controller';
}
return $controller;
}
/**
* @return array|string
*/
private function getControllerNameWithoutNamespace()
{
return class_basename($this->getControllerName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.controller.namespace')
?? ltrim(config('modules.paths.generator.controller.path', 'Http/Controllers'), config('modules.paths.app_folder'));
}
/**
* Get the stub file name based on the options
* @return string
*/
protected function getStubName()
{
if ($this->option('plain') === true) {
$stub = '/controller-plain.stub';
} elseif ($this->option('api') === true) {
$stub = '/controller-api.stub';
} else {
$stub = '/controller.stub';
}
return $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;
class EventMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-event';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new event class for the specified module';
public function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/event.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
public function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$eventPath = GenerateConfigReader::read('event');
return $path . $eventPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
protected function getFileName()
{
return Str::studly($this->argument('name'));
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.event.namespace')
?? ltrim(config('modules.paths.generator.event.path', 'Events'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the event.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
}

View File

@ -0,0 +1,115 @@
<?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;
class FactoryMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-factory';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new model factory for the specified module.';
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the model.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/factory.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'NAME' => $this->getModelName(),
'MODEL_NAMESPACE' => $this->getModelNamespace(),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$factoryPath = GenerateConfigReader::read('factory');
return $path . $factoryPath->getPath() . '/' . $this->getFileName();
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name')) . 'Factory.php';
}
/**
* @return mixed|string
*/
private function getModelName()
{
return Str::studly($this->argument('name'));
}
/**
* Get default namespace.
*
* @return string
*/
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.factory.namespace')
?? ltrim(config('modules.paths.generator.factory.path', 'Database/Factories'), config('modules.paths.app_folder', ''));
}
/**
* Get model namespace.
*
* @return string
*/
public function getModelNamespace(): string
{
$path = ltrim(config('modules.paths.generator.model.path', 'Entities'), config('modules.paths.app_folder', ''));
$path = str_replace('/', '\\', $path);
return $this->laravel['modules']->config('namespace') . '\\' . $this->laravel['modules']->findOrFail($this->getModuleName()) . '\\' . $path;
}
}

View File

@ -0,0 +1,105 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Console\Command;
use Nwidart\Modules\Exceptions\FileAlreadyExistException;
use Nwidart\Modules\Generators\FileGenerator;
abstract class GeneratorCommand extends Command
{
/**
* The name of 'name' argument.
*
* @var string
*/
protected $argumentName = '';
/**
* Get template contents.
*
* @return string
*/
abstract protected function getTemplateContents();
/**
* Get the destination file path.
*
* @return string
*/
abstract protected function getDestinationFilePath();
/**
* Execute the console command.
*/
public function handle(): int
{
$path = str_replace('\\', '/', $this->getDestinationFilePath());
if (!$this->laravel['files']->isDirectory($dir = dirname($path))) {
$this->laravel['files']->makeDirectory($dir, 0777, true);
}
$contents = $this->getTemplateContents();
try {
$this->components->task("Generating file {$path}", function () use ($path, $contents) {
$overwriteFile = $this->hasOption('force') ? $this->option('force') : false;
(new FileGenerator($path, $contents))->withFileOverwrite($overwriteFile)->generate();
});
} catch (FileAlreadyExistException $e) {
$this->components->error("File : {$path} already exists.");
return E_ERROR;
}
return 0;
}
/**
* Get class name.
*
* @return string
*/
public function getClass()
{
return class_basename($this->argument($this->argumentName));
}
/**
* Get default namespace.
*
* @return string
*/
public function getDefaultNamespace(): string
{
return '';
}
/**
* Get class namespace.
*
* @param \Nwidart\Modules\Module $module
*
* @return string
*/
public function getClassNamespace($module)
{
$extra = 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, '\\');
}
}

View File

@ -0,0 +1,111 @@
<?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 JobMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-job';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new job class for the specified module';
protected $argumentName = 'name';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.jobs.namespace')
?? ltrim(config('modules.paths.generator.jobs.path', 'Jobs'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the job.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['sync', null, InputOption::VALUE_NONE, 'Indicates that job should be synchronous.'],
];
}
/**
* Get template contents.
*
* @return string
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* Get the destination file path.
*
* @return string
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$jobPath = GenerateConfigReader::read('jobs');
return $path . $jobPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
/**
* @return string
*/
protected function getStubName(): string
{
if ($this->option('sync')) {
return '/job.stub';
}
return '/job-queued.stub';
}
}

View File

@ -0,0 +1,128 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Module;
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 ListenerMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-listener';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new event listener class for the specified module';
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the command.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['event', 'e', InputOption::VALUE_OPTIONAL, 'The event class being listened for.'],
['queued', null, InputOption::VALUE_NONE, 'Indicates the event listener should be queued.'],
];
}
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'NAMESPACE' => $this->getClassNamespace($module),
'EVENTNAME' => $this->getEventName($module),
'SHORTEVENTNAME' => $this->getShortEventName(),
'CLASS' => $this->getClass(),
]))->render();
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.listener.namespace')
?? ltrim(config('modules.paths.generator.listener.path', 'Listeners'), config('modules.paths.app_folder', ''));
}
protected function getEventName(Module $module)
{
$namespace = $this->laravel['modules']->config('namespace') . "\\" . $module->getStudlyName();
$eventPath = GenerateConfigReader::read('event');
$eventName = $namespace . "\\" . $eventPath->getPath() . "\\" . $this->option('event');
return str_replace('/', '\\', $eventName);
}
protected function getShortEventName()
{
return class_basename($this->option('event'));
}
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$listenerPath = GenerateConfigReader::read('listener');
return $path . $listenerPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
protected function getFileName()
{
return Str::studly($this->argument('name'));
}
/**
* @return string
*/
protected function getStubName(): string
{
if ($this->option('queued')) {
if ($this->option('event')) {
return '/listener-queued.stub';
}
return '/listener-queued-duck.stub';
}
if ($this->option('event')) {
return '/listener.stub';
}
return '/listener-duck.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;
class MailMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-mail';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new email class for the specified module';
protected $argumentName = 'name';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.emails.namespace')
?? ltrim(config('modules.paths.generator.emails.path', 'Emails'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the mailable.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get template contents.
*
* @return string
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/mail.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* Get the destination file path.
*
* @return string
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$mailPath = GenerateConfigReader::read('emails');
return $path . $mailPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
}

View File

@ -0,0 +1,100 @@
<?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;
class MiddlewareMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-middleware';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new middleware class for the specified module.';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.filter.namespace')
?? ltrim(config('modules.paths.generator.filter.path', 'Http/Middleware'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the command.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/middleware.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$middlewarePath = GenerateConfigReader::read('filter');
return $path . $middlewarePath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
/**
* Run the command.
*/
public function handle(): int
{
$this->components->info('Creating middleware...');
parent::handle();
return 0;
}
}

View File

@ -0,0 +1,169 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Support\Config\GenerateConfigReader;
use Nwidart\Modules\Support\Migrations\NameParser;
use Nwidart\Modules\Support\Migrations\SchemaParser;
use Nwidart\Modules\Support\Stub;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class MigrationMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-migration';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new migration for the specified module.';
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The migration name will be created.'],
['module', InputArgument::OPTIONAL, 'The name of module will be created.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['fields', null, InputOption::VALUE_OPTIONAL, 'The specified fields table.', null],
['plain', null, InputOption::VALUE_NONE, 'Create plain migration.'],
];
}
/**
* Get schema parser.
*
* @return SchemaParser
*/
public function getSchemaParser()
{
return new SchemaParser($this->option('fields'));
}
/**
* @throws \InvalidArgumentException
*
* @return mixed
*/
protected function getTemplateContents()
{
$parser = new NameParser($this->argument('name'));
if ($parser->isCreate()) {
return Stub::create('/migration/create.stub', [
'class' => $this->getClass(),
'table' => $parser->getTableName(),
'fields' => $this->getSchemaParser()->render(),
]);
} elseif ($parser->isAdd()) {
return Stub::create('/migration/add.stub', [
'class' => $this->getClass(),
'table' => $parser->getTableName(),
'fields_up' => $this->getSchemaParser()->up(),
'fields_down' => $this->getSchemaParser()->down(),
]);
} elseif ($parser->isDelete()) {
return Stub::create('/migration/delete.stub', [
'class' => $this->getClass(),
'table' => $parser->getTableName(),
'fields_down' => $this->getSchemaParser()->up(),
'fields_up' => $this->getSchemaParser()->down(),
]);
} elseif ($parser->isDrop()) {
return Stub::create('/migration/drop.stub', [
'class' => $this->getClass(),
'table' => $parser->getTableName(),
'fields' => $this->getSchemaParser()->render(),
]);
}
return Stub::create('/migration/plain.stub', [
'class' => $this->getClass(),
]);
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$generatorPath = GenerateConfigReader::read('migration');
return $path . $generatorPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return date('Y_m_d_His_') . $this->getSchemaName();
}
/**
* @return array|string
*/
private function getSchemaName()
{
return $this->argument('name');
}
/**
* @return string
*/
private function getClassName()
{
return Str::studly($this->argument('name'));
}
public function getClass()
{
return $this->getClassName();
}
/**
* Run the command.
*/
public function handle(): int
{
$this->components->info('Creating migration...');
if (parent::handle() === E_ERROR) {
return E_ERROR;
}
if (app()->environment() === 'testing') {
return 0;
}
return 0;
}
}

View File

@ -0,0 +1,244 @@
<?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 ModelMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'model';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-model';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new model for the specified module.';
public function handle(): int
{
if (parent::handle() === E_ERROR) {
return E_ERROR;
}
$this->handleOptionalMigrationOption();
$this->handleOptionalControllerOption();
$this->handleOptionalSeedOption();
$this->handleOptionalFactoryOption();
$this->handleOptionalRequestOption();
return 0;
}
/**
* Create a proper migration name:
* ProductDetail: product_details
* Product: products
* @return string
*/
private function createMigrationName()
{
$pieces = preg_split('/(?=[A-Z])/', $this->argument('model'), -1, PREG_SPLIT_NO_EMPTY);
$string = '';
foreach ($pieces as $i => $piece) {
if ($i + 1 < count($pieces)) {
$string .= strtolower($piece) . '_';
} else {
$string .= Str::plural(strtolower($piece));
}
}
return $string;
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['model', InputArgument::REQUIRED, 'The name of model will be created.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['fillable', null, InputOption::VALUE_OPTIONAL, 'The fillable attributes.', null],
['migration', 'm', InputOption::VALUE_NONE, 'Flag to create associated migrations', null],
['controller', 'c', InputOption::VALUE_NONE, 'Flag to create associated controllers', null],
['seed', 's', InputOption::VALUE_NONE, 'Create a new seeder for the model', null],
['factory', 'f', InputOption::VALUE_NONE, 'Create a new factory for the model', null],
['request', 'r', InputOption::VALUE_NONE, 'Create a new request for the model', null],
];
}
/**
* Create the migration file with the given model if migration flag was used
*/
private function handleOptionalMigrationOption()
{
if ($this->option('migration') === true) {
$migrationName = 'create_' . $this->createMigrationName() . '_table';
$this->call('module:make-migration', ['name' => $migrationName, 'module' => $this->argument('module')]);
}
}
/**
* Create the controller file for the given model if controller flag was used
*/
private function handleOptionalControllerOption()
{
if ($this->option('controller') === true) {
$controllerName = "{$this->getModelName()}Controller";
$this->call('module:make-controller', array_filter([
'controller' => $controllerName,
'module' => $this->argument('module'),
]));
}
}
/**
* Create a seeder file for the model.
*
* @return void
*/
protected function handleOptionalSeedOption()
{
if ($this->option('seed') === true) {
$seedName = "{$this->getModelName()}Seeder";
$this->call('module:make-seed', array_filter([
'name' => $seedName,
'module' => $this->argument('module'),
]));
}
}
/**
* Create a seeder file for the model.
*
* @return void
*/
protected function handleOptionalFactoryOption()
{
if ($this->option('factory') === true) {
$this->call('module:make-factory', array_filter([
'name' => $this->getModelName(),
'module' => $this->argument('module'),
]));
}
}
/**
* Create a request file for the model.
*
* @return void
*/
protected function handleOptionalRequestOption()
{
if ($this->option('request') === true) {
$requestName = "{$this->getModelName()}Request";
$this->call('module:make-request', array_filter([
'name' => $requestName,
'module' => $this->argument('module'),
]));
}
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/model.stub', [
'NAME' => $this->getModelName(),
'FILLABLE' => $this->getFillable(),
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
'LOWER_NAME' => $module->getLowerName(),
'MODULE' => $this->getModuleName(),
'STUDLY_NAME' => $module->getStudlyName(),
'MODULE_NAMESPACE' => $this->laravel['modules']->config('namespace'),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$modelPath = GenerateConfigReader::read('model');
return $path . $modelPath->getPath() . '/' . $this->getModelName() . '.php';
}
/**
* @return mixed|string
*/
private function getModelName()
{
return Str::studly($this->argument('model'));
}
/**
* @return string
*/
private function getFillable()
{
$fillable = $this->option('fillable');
if (!is_null($fillable)) {
$arrays = explode(',', $fillable);
return json_encode($arrays);
}
return '[]';
}
/**
* Get default namespace.
*
* @return string
*/
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.model.namespace')
?? ltrim(config('modules.paths.generator.model.path', 'Models'), config('modules.paths.app_folder', ''));
}
}

View File

@ -0,0 +1,111 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Process;
use Nwidart\Modules\Contracts\ActivatorInterface;
use Nwidart\Modules\Generators\ModuleGenerator;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class ModuleMakeCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new module.';
/**
* Execute the console command.
*/
public function handle(): int
{
$names = $this->argument('name');
$success = true;
foreach ($names as $name) {
$code = with(new ModuleGenerator($name))
->setFilesystem($this->laravel['files'])
->setModule($this->laravel['modules'])
->setConfig($this->laravel['config'])
->setActivator($this->laravel[ActivatorInterface::class])
->setConsole($this)
->setComponent($this->components)
->setForce($this->option('force'))
->setType($this->getModuleType())
->setActive(!$this->option('disabled'))
->setVendor($this->option('author-vendor'))
->setAuthor($this->option('author-name'), $this->option('author-email'))
->generate();
if ($code === E_ERROR) {
$success = false;
}
}
// to discover new service providers
Process::path(base_path())
->command('composer dump-autoload')
->run()->output();
return $success ? 0 : E_ERROR;
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::IS_ARRAY, 'The names of modules will be created.'],
];
}
protected function getOptions()
{
return [
['plain', 'p', InputOption::VALUE_NONE, 'Generate a plain module (without some resources).'],
['api', null, InputOption::VALUE_NONE, 'Generate an api module.'],
['web', null, InputOption::VALUE_NONE, 'Generate a web module.'],
['disabled', 'd', InputOption::VALUE_NONE, 'Do not enable the module at creation.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when the module already exists.'],
['author-name', null, InputOption::VALUE_OPTIONAL, 'Author name.'],
['author-email', null, InputOption::VALUE_OPTIONAL, 'Author email.'],
['author-vendor', null, InputOption::VALUE_OPTIONAL, 'Author vendor.'],
];
}
/**
* Get module type .
*
* @return string
*/
private function getModuleType()
{
$isPlain = $this->option('plain');
$isApi = $this->option('api');
if ($isPlain && $isApi) {
return 'web';
}
if ($isPlain) {
return 'plain';
} elseif ($isApi) {
return 'api';
} else {
return 'web';
}
}
}

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;
final class NotificationMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-notification';
protected $argumentName = 'name';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new notification class for the specified module.';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.notifications.namespace')
?? ltrim(config('modules.paths.generator.notifications.path', 'Notifications'), config('modules.paths.app_folder', ''));
}
/**
* Get template contents.
*
* @return string
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/notification.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* Get the destination file path.
*
* @return string
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$notificationPath = GenerateConfigReader::read('notifications');
return $path . $notificationPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the notification class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
}

View File

@ -0,0 +1,133 @@
<?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;
class ObserverMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-observer';
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new observer for the specified module.';
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The observer name will be created.'],
['module', InputArgument::OPTIONAL, 'The name of module will be created.'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/observer.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'NAME' => $this->getModelName(),
'MODEL_NAMESPACE' => $this->getModelNamespace(),
'NAME_VARIABLE' => $this->getModelVariable(),
]))->render();
}
/**
* Get model namespace.
*
* @return string
*/
public function getModelNamespace(): string
{
$path = $this->laravel['modules']->config('paths.generator.model.path', 'Entities');
$path = str_replace('/', '\\', $path);
return $this->laravel['modules']->config('namespace') . '\\' . $this->laravel['modules']->findOrFail($this->getModuleName()) . '\\' . $path;
}
/**
* @return mixed|string
*/
private function getModelName()
{
return Str::studly($this->argument('name'));
}
/**
* @return mixed|string
*/
private function getModelVariable(): string
{
return '$' . Str::lower($this->argument('name'));
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$observerPath = GenerateConfigReader::read('observer');
return $path . $observerPath->getPath() . '/' . $this->getFileName();
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name')) . 'Observer.php';
}
public function handle(): int
{
$this->components->info('Creating observer...');
parent::handle();
return 0;
}
/**
* Get default namespace.
*
* @return string
*/
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.observer.namespace')
?? ltrim(config('modules.paths.generator.observer.path', 'Observers'), config('modules.paths.app_folder', ''));
}
}

View File

@ -0,0 +1,87 @@
<?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;
class PolicyMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-policy';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new policy class for the specified module.';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.policies.namespace')
?? ltrim(config('modules.paths.generator.policies.path', 'Policies'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the policy class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/policy.plain.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$policyPath = GenerateConfigReader::read('policies');
return $path . $policyPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
}

View File

@ -0,0 +1,114 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Support\Str;
use Nwidart\Modules\Module;
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 ProviderMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-provider';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new service provider class for the specified module.';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.provider.namespace')
?? ltrim(config('modules.paths.generator.provider.path', 'Providers'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The service provider name.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['master', null, InputOption::VALUE_NONE, 'Indicates the master service provider', null],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$stub = $this->option('master') ? 'scaffold/provider' : 'provider';
/** @var Module $module */
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/' . $stub . '.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
'LOWER_NAME' => $module->getLowerName(),
'MODULE' => $this->getModuleName(),
'NAME' => $this->getFileName(),
'STUDLY_NAME' => $module->getStudlyName(),
'MODULE_NAMESPACE' => $this->laravel['modules']->config('namespace'),
'PATH_VIEWS' => GenerateConfigReader::read('views')->getPath(),
'PATH_LANG' => GenerateConfigReader::read('lang')->getPath(),
'PATH_CONFIG' => GenerateConfigReader::read('config')->getPath(),
'MIGRATIONS_PATH' => GenerateConfigReader::read('migration')->getPath(),
'FACTORIES_PATH' => GenerateConfigReader::read('factory')->getPath(),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$generatorPath = GenerateConfigReader::read('provider');
return $path . $generatorPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
}

View File

@ -0,0 +1,87 @@
<?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;
class RequestMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-request';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new form request class for the specified module.';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.request.namespace')
?? ltrim(config('modules.paths.generator.request.path', 'Http/Requests'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the form request class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/request.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$requestPath = GenerateConfigReader::read('request');
return $path . $requestPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
}

View File

@ -0,0 +1,101 @@
<?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 ResourceMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-resource';
protected $description = 'Create a new resource class for the specified module.';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.resource.namespace')
?? ltrim(config('modules.paths.generator.resource.path', 'Transformers'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the resource class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
protected function getOptions()
{
return [
['collection', 'c', InputOption::VALUE_NONE, 'Create a resource collection.'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub($this->getStubName(), [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$resourcePath = GenerateConfigReader::read('resource');
return $path . $resourcePath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
/**
* Determine if the command is generating a resource collection.
*
* @return bool
*/
protected function collection(): bool
{
return $this->option('collection') ||
Str::endsWith($this->argument('name'), 'Collection');
}
/**
* @return string
*/
protected function getStubName(): string
{
if ($this->collection()) {
return '/resource-collection.stub';
}
return '/resource.stub';
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace Nwidart\Modules\Commands\Make;
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 RouteProviderMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'module';
/**
* The command name.
*
* @var string
*/
protected $name = 'module:route-provider';
/**
* The command description.
*
* @var string
*/
protected $description = 'Create a new route service provider for the specified module.';
/**
* The command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
protected function getOptions()
{
return [
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when the file already exists.'],
];
}
/**
* Get template contents.
*
* @return string
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/route-provider.stub', [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getFileName(),
'MODULE_NAMESPACE' => $this->laravel['modules']->config('namespace'),
'MODULE' => $this->getModuleName(),
'CONTROLLER_NAMESPACE' => $this->getControllerNameSpace(),
'WEB_ROUTES_PATH' => $this->getWebRoutesPath(),
'API_ROUTES_PATH' => $this->getApiRoutesPath(),
'LOWER_NAME' => $module->getLowerName(),
]))->render();
}
/**
* @return string
*/
private function getFileName()
{
return 'RouteServiceProvider';
}
/**
* Get the destination file path.
*
* @return string
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$generatorPath = GenerateConfigReader::read('provider');
return $path . $generatorPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return mixed
*/
protected function getWebRoutesPath()
{
return '/' . $this->laravel['modules']->config('stubs.files.routes/web', 'Routes/web.php');
}
/**
* @return mixed
*/
protected function getApiRoutesPath()
{
return '/' . $this->laravel['modules']->config('stubs.files.routes/api', 'Routes/api.php');
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.provider.namespace')
?? ltrim(config('modules.paths.generator.provider.path', 'Providers'), config('modules.paths.app_folder', ''));
}
/**
* @return string
*/
private function getControllerNameSpace(): string
{
$module = $this->laravel['modules'];
return str_replace('/', '\\', $module->config('paths.generator.controller.namespace') ?: $module->config('paths.generator.controller.path', 'Controller'));
}
}

View File

@ -0,0 +1,104 @@
<?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 RuleMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
/**
* The name of argument name.
*
* @var string
*/
protected $argumentName = 'name';
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:make-rule';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new validation rule for the specified module.';
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.rules.namespace')
?? ltrim(config('modules.paths.generator.rules.path', 'Rules'), config('modules.paths.app_folder', ''));
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the rule class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['implicit', 'i', InputOption::VALUE_NONE, 'Generate an implicit rule'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
$stub = $this->option('implicit')
? '/rule.implicit.stub'
: '/rule.stub';
return (new Stub($stub, [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getFileName(),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$rulePath = GenerateConfigReader::read('rules');
return $path . $rulePath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
}

View File

@ -0,0 +1,103 @@
<?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\CanClearModulesCache;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class SeedMakeCommand extends GeneratorCommand
{
use CanClearModulesCache;
use ModuleCommandTrait;
protected $argumentName = 'name';
/**
* The console command name.
*/
protected $name = 'module:make-seed';
/**
* The console command description.
*/
protected $description = 'Generate new seeder for the specified module.';
/**
* Get the console command arguments.
*/
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of seeder will be created.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get the console command options.
*/
protected function getOptions(): array
{
return [
[
'master',
null,
InputOption::VALUE_NONE,
'Indicates the seeder will created is a master database seeder.',
],
];
}
protected function getTemplateContents(): mixed
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
return (new Stub('/seeder.stub', [
'NAME' => $this->getSeederName(),
'MODULE' => $this->getModuleName(),
'NAMESPACE' => $this->getClassNamespace($module),
]))->render();
}
protected function getDestinationFilePath(): mixed
{
$this->clearCache();
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$seederPath = GenerateConfigReader::read('seeder');
return $path . $seederPath->getPath() . '/' . $this->getSeederName() . '.php';
}
/**
* Get the seeder name.
*/
private function getSeederName(): string
{
$string = $this->argument('name');
$string .= $this->option('master') ? 'Database' : '';
$suffix = 'Seeder';
if (strpos($string, $suffix) === false) {
$string .= $suffix;
}
return Str::studly($string);
}
/**
* Get default namespace.
*/
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.seeder.namespace')
?? ltrim(config('modules.paths.generator.seeder.path', 'Database/Seeders'), config('modules.paths.app_folder', ''));
}
}

View File

@ -0,0 +1,66 @@
<?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;
class ServiceMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-service';
protected $description = 'Generate a service class for the specified module.';
public function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$servicePath = GenerateConfigReader::read('service');
return $path . $servicePath->getPath() . '/' . $this->getServiceName() . '.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 service class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
protected function getServiceName(): array|string
{
return Str::studly($this->argument('name'));
}
private function getClassNameWithoutNamespace(): array|string
{
return class_basename($this->getServiceName());
}
public function getDefaultNamespace(): string
{
return config('modules.paths.generator.service.namespace')
?? ltrim(config('modules.paths.generator.service.path', 'Services'), config('modules.paths.app_folder'));
}
protected function getStubName(): string
{
return '/service.stub';
}
}

View File

@ -0,0 +1,97 @@
<?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 TestMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-test';
protected $description = 'Create a new test class for the specified module.';
public function getDefaultNamespace(): string
{
if ($this->option('feature')) {
return config('modules.paths.generator.test-feature.namespace')
?? config('modules.paths.generator.test-feature.path', 'tests/Feature');
}
return config('modules.paths.generator.test-unit.namespace')
?? config('modules.paths.generator.test-unit.path', 'tests/Unit');
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the form request class.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['feature', null, InputOption::VALUE_NONE, 'Create a feature test.'],
];
}
/**
* @return mixed
*/
protected function getTemplateContents()
{
$module = $this->laravel['modules']->findOrFail($this->getModuleName());
$stub = '/unit-test.stub';
if ($this->option('feature')) {
$stub = '/feature-test.stub';
}
return (new Stub($stub, [
'NAMESPACE' => $this->getClassNamespace($module),
'CLASS' => $this->getClass(),
]))->render();
}
/**
* @return mixed
*/
protected function getDestinationFilePath()
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
if ($this->option('feature')) {
$testPath = GenerateConfigReader::read('test-feature');
} else {
$testPath = GenerateConfigReader::read('test-unit');
}
return $path . $testPath->getPath() . '/' . $this->getFileName() . '.php';
}
/**
* @return string
*/
private function getFileName()
{
return Str::studly($this->argument('name'));
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace Nwidart\Modules\Commands\Make;
use Illuminate\Foundation\Inspiring;
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;
class ViewMakeCommand extends GeneratorCommand
{
use ModuleCommandTrait;
protected $argumentName = 'name';
protected $name = 'module:make-view';
protected $description = 'Create a new view for the specified module.';
protected function getArguments(): array
{
return [
['name', InputArgument::REQUIRED, 'The name of the view.'],
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
protected function getTemplateContents(): string
{
return (new Stub('/view.stub', ['QUOTE' => Inspiring::quotes()->random()]))->render();
}
protected function getDestinationFilePath(): string
{
$path = $this->laravel['modules']->getModulePath($this->getModuleName());
$factoryPath = GenerateConfigReader::read('views');
return $path . $factoryPath->getPath() . '/' . $this->getFileName();
}
/**
* @return string
*/
private function getFileName(): string
{
return Str::lower($this->argument('name')) . '.blade.php';
}
}

View File

@ -0,0 +1,91 @@
<?php
namespace Nwidart\Modules\Commands;
use Illuminate\Console\Command;
use Nwidart\Modules\Traits\ModuleCommandTrait;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class MigrateFreshCommand extends Command
{
use ModuleCommandTrait;
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:migrate-fresh';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Drop all database tables and re-run all migrations';
/**
* Execute the console command.
*/
public function handle(): int
{
$module = $this->argument('module');
if ($module && !$this->getModuleName()) {
$this->error("Module [$module] does not exists.");
return E_ERROR;
}
$this->call('migrate:fresh');
$this->call('module:migrate', [
'module' => $this->getModuleName(),
'--database' => $this->option('database'),
'--force' => $this->option('force'),
'--seed' => $this->option('seed'),
]);
return 0;
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run.'],
];
}
public function getModuleName()
{
$module = $this->argument('module');
if (!$module) {
return null;
}
$module = app('modules')->find($module);
return $module ? $module->getStudlyName() : null;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace Nwidart\Modules\Commands\Publish;
use Nwidart\Modules\Commands\BaseCommand;
use Nwidart\Modules\Publishing\AssetPublisher;
class PublishCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:publish';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Publish a module\'s assets to the application';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Publishing Assets <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
with(new AssetPublisher($module))
->setRepository($this->laravel['modules'])
->setConsole($this)
->publish();
});
}
public function getInfo(): string|null
{
return 'Publishing module asset files ...';
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace Nwidart\Modules\Commands\Publish;
use Illuminate\Support\Str;
use Nwidart\Modules\Commands\BaseCommand;
use Symfony\Component\Console\Input\InputOption;
class PublishConfigurationCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:publish-config';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Publish a module\'s config files to the application';
public function executeAction($name): void
{
$this->call('vendor:publish', [
'--provider' => $this->getServiceProviderForModule($name),
'--force' => $this->option('force'),
'--tag' => ['config'],
]);
}
public function getInfo(): string|null
{
return 'Publishing module config files ...';
}
/**
* @param string $module
* @return string
*/
private function getServiceProviderForModule($module): string
{
$namespace = $this->laravel['config']->get('modules.namespace');
$studlyName = Str::studly($module);
$provider = $this->laravel['config']->get('modules.paths.generator.provider.path');
$provider = str_replace('/', '\\', $provider);
return "$namespace\\$studlyName\\$provider\\{$studlyName}ServiceProvider";
}
/**
* @return array
*/
protected function getOptions(): array
{
return [
['--force', '-f', InputOption::VALUE_NONE, 'Force the publishing of config files'],
];
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Nwidart\Modules\Commands\Publish;
use Nwidart\Modules\Commands\BaseCommand;
use Nwidart\Modules\Migrations\Migrator;
use Nwidart\Modules\Publishing\MigrationPublisher;
class PublishMigrationCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:publish-migration';
/**
* The console command description.
*
* @var string
*/
protected $description = "Publish a module's migrations to the application";
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Publishing Migration <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
with(new MigrationPublisher(new Migrator($module, $this->getLaravel())))
->setRepository($this->laravel['modules'])
->setConsole($this)
->publish();
});
}
public function getInfo(): string|null
{
return 'Publishing module migrations ...';
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Nwidart\Modules\Commands\Publish;
use Nwidart\Modules\Commands\BaseCommand;
use Nwidart\Modules\Publishing\LangPublisher;
class PublishTranslationCommand extends BaseCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:publish-translation';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Publish a module\'s translations to the application';
public function executeAction($name): void
{
$module = $this->getModuleModel($name);
$this->components->task("Publishing Translations <fg=cyan;options=bold>{$module->getName()}</> Module", function () use ($module) {
with(new LangPublisher($module))
->setRepository($this->laravel['modules'])
->setConsole($this)
->publish();
});
}
public function getInfo(): string|null
{
return 'Publishing module translations ...';
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace Nwidart\Modules\Commands;
use Illuminate\Console\Command;
class SetupCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'module:setup';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Setting up modules folders for first use.';
/**
* Execute the console command.
*/
public function handle(): int
{
$code = $this->generateModulesFolder();
return $this->generateAssetsFolder() | $code;
}
/**
* Generate the modules folder.
*/
public function generateModulesFolder()
{
return $this->generateDirectory(
$this->laravel['modules']->config('paths.modules'),
'Modules directory created successfully',
'Modules directory already exist'
);
}
/**
* Generate the assets folder.
*/
public function generateAssetsFolder()
{
return $this->generateDirectory(
$this->laravel['modules']->config('paths.assets'),
'Assets directory created successfully',
'Assets directory already exist'
);
}
/**
* Generate the specified directory by given $dir.
*
* @param $dir
* @param $success
* @param $error
* @return int
*/
protected function generateDirectory($dir, $success, $error): int
{
if (!$this->laravel['files']->isDirectory($dir)) {
$this->laravel['files']->makeDirectory($dir, 0755, true, true);
$this->components->info($success);
return 0;
}
$this->components->error($error);
return E_ERROR;
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace $NAMESPACE$;
class $CLASS$
{
/**
* Create a new channel instance.
*/
public function __construct()
{
//
}
/**
* Authenticate the user's access to the channel.
*/
public function join(Operator $user): array|bool
{
//
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class $CLASS$ extends Command
{
/**
* The name and signature of the console command.
*/
protected $signature = '$COMMAND_NAME$';
/**
* The console command description.
*/
protected $description = 'Command description.';
/**
* Create a new command instance.
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle()
{
//
}
/**
* Get the console command arguments.
*/
protected function getArguments(): array
{
return [
['example', InputArgument::REQUIRED, 'An example argument.'],
];
}
/**
* Get the console command options.
*/
protected function getOptions(): array
{
return [
['example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null],
];
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace $NAMESPACE$;
use Illuminate\View\Component;
use Illuminate\View\View;
class $CLASS$ extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view/contents that represent the component.
*/
public function render(): View|string
{
return view('$LOWER_NAME$::$COMPONENT_NAME$');
}
}

View File

@ -0,0 +1,3 @@
<div>
<!-- $QUOTE$ -->
</div>

View File

@ -0,0 +1,30 @@
{
"name": "$VENDOR$/$LOWER_NAME$",
"description": "",
"authors": [
{
"name": "$AUTHOR_NAME$",
"email": "$AUTHOR_EMAIL$"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"$MODULE_NAMESPACE$\\$STUDLY_NAME$\\": "$APP_FOLDER_NAME$",
"$MODULE_NAMESPACE$\\$STUDLY_NAME$\\Database\\Factories\\": "database/factories/",
"$MODULE_NAMESPACE$\\$STUDLY_NAME$\\Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"$MODULE_NAMESPACE$\\$STUDLY_NAME$\\Tests\\": "tests/"
}
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace $CLASS_NAMESPACE$;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class $CLASS$ extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
return response()->json([]);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
return response()->json([]);
}
/**
* Show the specified resource.
*/
public function show($id)
{
//
return response()->json([]);
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id)
{
//
return response()->json([]);
}
/**
* Remove the specified resource from storage.
*/
public function destroy($id)
{
//
return response()->json([]);
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace $CLASS_NAMESPACE$;
use Illuminate\Routing\Controller;
class $CLASS$ extends Controller
{
}

View File

@ -0,0 +1,67 @@
<?php
namespace $CLASS_NAMESPACE$;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class $CLASS$ extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return view('$LOWER_NAME$::index');
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
return view('$LOWER_NAME$::create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request): RedirectResponse
{
//
}
/**
* Show the specified resource.
*/
public function show($id)
{
return view('$LOWER_NAME$::show');
}
/**
* Show the form for editing the specified resource.
*/
public function edit($id)
{
return view('$LOWER_NAME$::edit');
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id): RedirectResponse
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy($id)
{
//
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class $CLASS$
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public function __construct()
{
//
}
/**
* Get the channels the event should be broadcast on.
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Database\Eloquent\Factories\Factory;
class $NAME$Factory extends Factory
{
/**
* The name of the factory's corresponding model.
*/
protected $model = \$MODEL_NAMESPACE$\$NAME$::class;
/**
* Define the model's default state.
*/
public function definition(): array
{
return [];
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace $NAMESPACE$;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class $CLASS$ extends TestCase
{
/**
* A basic feature test example.
*/
public function testExample(): void
{
$response = $this->get('/');
$response->assertStatus(200);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class $CLASS$ implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*/
public function __construct()
{
//
}
/**
* Execute the job.
*/
public function handle(): void
{
//
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Bus\Queueable;
use Illuminate\Foundation\Bus\Dispatchable;
class $CLASS$ implements ShouldQueue
{
use Dispatchable, Queueable;
/**
* Create a new job instance.
*/
public function __construct()
{
//
}
/**
* Execute the job.
*/
public function handle(): void
{
//
}
}

View File

@ -0,0 +1,11 @@
{
"name": "$STUDLY_NAME$",
"alias": "$LOWER_NAME$",
"description": "",
"keywords": [],
"priority": 0,
"providers": [
"$MODULE_NAMESPACE$\\$STUDLY_NAME$\\$PROVIDER_NAMESPACE$\\$STUDLY_NAME$ServiceProvider"
],
"files": []
}

View File

@ -0,0 +1,25 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class $CLASS$
{
/**
* Create the event listener.
*/
public function __construct()
{
//
}
/**
* Handle the event.
*/
public function handle($event): void
{
//
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class $CLASS$ implements ShouldQueue
{
use InteractsWithQueue;
/**
* Create the event listener
*/
public function __construct()
{
//
}
/**
* Handle the event.
*/
public function handle($event): void
{
//
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace $NAMESPACE$;
use $EVENTNAME$;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class $CLASS$ implements ShouldQueue
{
use InteractsWithQueue;
/**
* Create the event listener.
*/
public function __construct()
{
//
}
/**
* Handle the event.
*/
public function handle($SHORTEVENTNAME$ $event): void
{
//
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace $NAMESPACE$;
use $EVENTNAME$;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class $CLASS$
{
/**
* Create the event listener.
*/
public function __construct()
{
//
}
/**
* Handle the event.
*/
public function handle($SHORTEVENTNAME$ $event): void
{
//
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class $CLASS$ extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct()
{
//
}
/**
* Build the message.
*/
public function build(): self
{
return $this->view('view.name');
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace $NAMESPACE$;
use Closure;
use Illuminate\Http\Request;
class $CLASS$
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next)
{
return $next($request);
}
}

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('$TABLE$', function (Blueprint $table) {
$FIELDS_UP$
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('$TABLE$', function (Blueprint $table) {
$FIELDS_DOWN$
});
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('$TABLE$', function (Blueprint $table) {
$table->id();
$FIELDS$
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('$TABLE$');
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('$TABLE$', function (Blueprint $table) {
$FIELDS_UP$
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('$TABLE$', function (Blueprint $table) {
$FIELDS_DOWN$
});
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::dropIfExists('$TABLE$');
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::create('$TABLE$', function (Blueprint $table) {
$table->id();
$FIELDS$
$table->timestamps();
});
}
};

View File

@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
//
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

View File

@ -0,0 +1,22 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use $MODULE_NAMESPACE$\$MODULE$\Database\Factories\$NAME$Factory;
class $CLASS$ extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*/
protected $fillable = $FILLABLE$;
protected static function newFactory(): $NAME$Factory
{
//return $NAME$Factory::new();
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class $CLASS$ extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*/
public function __construct()
{
//
}
/**
* Get the notification's delivery channels.
*/
public function via($notifiable): array
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*/
public function toMail($notifiable): MailMessage
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', 'https://laravel.com')
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*/
public function toArray($notifiable): array
{
return [];
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace $NAMESPACE$;
use $MODEL_NAMESPACE$\$NAME$;
class $NAME$Observer
{
/**
* Handle the $NAME$ "created" event.
*/
public function created($NAME$ $NAME_VARIABLE$): void
{
//
}
/**
* Handle the $NAME$ "updated" event.
*/
public function updated($NAME$ $NAME_VARIABLE$): void
{
//
}
/**
* Handle the $NAME$ "deleted" event.
*/
public function deleted($NAME$ $NAME_VARIABLE$): void
{
//
}
/**
* Handle the $NAME$ "restored" event.
*/
public function restored($NAME$ $NAME_VARIABLE$): void
{
//
}
/**
* Handle the $NAME$ "force deleted" event.
*/
public function forceDeleted($NAME$ $NAME_VARIABLE$): void
{
//
}
}

View File

@ -0,0 +1,15 @@
{
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"axios": "^1.1.2",
"laravel-vite-plugin": "^0.7.5",
"sass": "^1.69.5",
"postcss": "^8.3.7",
"vite": "^4.0.0"
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Auth\Access\HandlesAuthorization;
class $CLASS$
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*/
public function __construct()
{
//
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Support\ServiceProvider;
class $CLASS$ extends ServiceProvider
{
/**
* Register the service provider.
*/
public function register(): void
{
//
}
/**
* Get the services provided by the provider.
*/
public function provides(): array
{
return [];
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Foundation\Http\FormRequest;
class $CLASS$ extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
//
];
}
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
}

Some files were not shown because too many files have changed in this diff Show More