add Auth module

This commit is contained in:
khanh97dev 2023-11-09 14:43:39 +07:00
parent 124f4088cc
commit 2788131cca
92 changed files with 2519 additions and 10 deletions

View File

@ -0,0 +1,67 @@
<?php
namespace Modules\Auth\app\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class AuthController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return view('auth::index');
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
return view('auth::create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request): RedirectResponse
{
//
}
/**
* Show the specified resource.
*/
public function show($id)
{
return view('auth::show');
}
/**
* Show the form for editing the specified resource.
*/
public function edit($id)
{
return view('auth::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,16 @@
<?php
namespace Modules\Auth\app\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ForgotController extends Controller
{
public function forgot(Request $request)
{
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Modules\Auth\app\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Http\Middleware\Authenticate;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => Auth::factory()->getTTL() * 60
]);
}
/**
* handle login api
*
* @param \Illuminate\Http\Request $request
* @return void
*/
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if ($token = Auth::attempt($credentials)) {
return $this->respondWithToken($token);
}
return response()->json([
'message' => 'Unauthenticated.'
], 401);
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Modules\Auth\app\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class RegisterController extends Controller
{
public function register(Request $request)
{
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Modules\Auth\app\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class UserController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function users()
{
return User::all();
}
}

View File

View File

View File

View File

@ -0,0 +1,114 @@
<?php
namespace Modules\Auth\app\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
protected string $moduleName = 'Auth';
protected string $moduleNameLower = 'auth';
/**
* Boot the application events.
*/
public function boot(): void
{
$this->registerCommands();
$this->registerCommandSchedules();
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->moduleName, 'database/migrations'));
}
/**
* Register the service provider.
*/
public function register(): void
{
$this->app->register(RouteServiceProvider::class);
}
/**
* Register commands in the format of Command::class
*/
protected function registerCommands(): void
{
// $this->commands([]);
}
/**
* Register command Schedules.
*/
protected function registerCommandSchedules(): void
{
// $this->app->booted(function () {
// $schedule = $this->app->make(Schedule::class);
// $schedule->command('inspire')->hourly();
// });
}
/**
* Register translations.
*/
public function registerTranslations(): void
{
$langPath = resource_path('lang/modules/'.$this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
$this->loadJsonTranslationsFrom($langPath);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, 'lang'), $this->moduleNameLower);
$this->loadJsonTranslationsFrom(module_path($this->moduleName, 'lang'));
}
}
/**
* Register config.
*/
protected function registerConfig(): void
{
$this->publishes([module_path($this->moduleName, 'config/config.php') => config_path($this->moduleNameLower.'.php')], 'config');
$this->mergeConfigFrom(module_path($this->moduleName, 'config/config.php'), $this->moduleNameLower);
}
/**
* Register views.
*/
public function registerViews(): void
{
$viewPath = resource_path('views/modules/'.$this->moduleNameLower);
$sourcePath = module_path($this->moduleName, 'resources/views');
$this->publishes([$sourcePath => $viewPath], ['views', $this->moduleNameLower.'-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
$componentNamespace = str_replace('/', '\\', config('modules.namespace').'\\'.$this->moduleName.'\\'.config('modules.paths.generator.component-class.path'));
Blade::componentNamespace($componentNamespace, $this->moduleNameLower);
}
/**
* Get the services provided by the provider.
*/
public function provides(): array
{
return [];
}
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (config('view.paths') as $path) {
if (is_dir($path.'/modules/'.$this->moduleNameLower)) {
$paths[] = $path.'/modules/'.$this->moduleNameLower;
}
}
return $paths;
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Modules\Auth\app\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* The module namespace to assume when generating URLs to actions.
*/
protected string $moduleNamespace = 'Modules\Auth\app\Http\Controllers';
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*/
public function boot(): void
{
parent::boot();
}
/**
* Define the routes for the application.
*/
public function map(): void
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*/
protected function mapWebRoutes(): void
{
Route::middleware('web')
->namespace($this->moduleNamespace)
->group(module_path('Auth', '/routes/web.php'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
->namespace($this->moduleNamespace)
->group(module_path('Auth', '/routes/api.php'));
}
}

View File

@ -0,0 +1,31 @@
{
"name": "nwidart/auth",
"description": "",
"authors": [
{
"name": "Nicolas Widart",
"email": "n.widart@gmail.com"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"Modules\\Auth\\": "",
"Modules\\Auth\\App\\": "app/",
"Modules\\Auth\\Database\\Factories\\": "database/factories/",
"Modules\\Auth\\Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Modules\\Auth\\Tests\\": "tests/"
}
}
}

View File

View File

@ -0,0 +1,5 @@
<?php
return [
'name' => 'Auth',
];

View File

View File

View File

@ -0,0 +1,16 @@
<?php
namespace Modules\Auth\database\seeders;
use Illuminate\Database\Seeder;
class AuthDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// $this->call([]);
}
}

View File

11
Modules/Auth/module.json Normal file
View File

@ -0,0 +1,11 @@
{
"name": "Auth",
"alias": "auth",
"description": "",
"keywords": [],
"priority": 0,
"providers": [
"Modules\\Auth\\app\\Providers\\AuthServiceProvider"
],
"files": []
}

15
Modules/Auth/package.json Normal file
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

View File

View File

View File

@ -0,0 +1,7 @@
@extends('auth::layouts.master')
@section('content')
<h1>Hello World</h1>
<p>Module: {!! config('auth.name') !!}</p>
@endsection

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Auth Module - {{ config('app.name', 'Laravel') }}</title>
<meta name="description" content="{{ $description ?? '' }}">
<meta name="keywords" content="{{ $keywords ?? '' }}">
<meta name="author" content="{{ $author ?? '' }}">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
{{-- Vite CSS --}}
{{-- {{ module_vite('build-auth', 'resources/assets/sass/app.scss') }} --}}
</head>
<body>
@yield('content')
{{-- Vite JS --}}
{{-- {{ module_vite('build-auth', 'resources/assets/js/app.js') }} --}}
</body>

View File

View File

@ -0,0 +1,29 @@
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Modules\Auth\app\Http\Controllers\ForgotController;
use Modules\Auth\app\Http\Controllers\LoginController;
use Modules\Auth\app\Http\Controllers\RegisterController;
use Modules\Auth\app\Http\Controllers\UserController;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware(['api'])
->prefix('v1')
->name('api.v1.')
->group(function () {
Route::get('users', [UserController::class, 'users']);
Route::post('login', [LoginController::class, 'login']);
Route::post('register', [RegisterController::class, 'register']);
Route::post('forgot', [ForgotController::class, 'forgot']);
});

View File

@ -0,0 +1,19 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\Auth\app\Http\Controllers\AuthController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::group([], function () {
// Route::resource('auth', AuthController::class)->names('auth');
});

View File

View File

View File

@ -0,0 +1,26 @@
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
build: {
outDir: '../../public/build-auth',
emptyOutDir: true,
manifest: true,
},
plugins: [
laravel({
publicDirectory: '../../public',
buildDirectory: 'build-auth',
input: [
__dirname + '/resources/assets/sass/app.scss',
__dirname + '/resources/assets/js/app.js'
],
refresh: true,
}),
],
});
//export const paths = [
// 'Modules/$STUDLY_NAME$/resources/assets/sass/app.scss',
// 'Modules/$STUDLY_NAME$/resources/assets/js/app.js',
//];

View File

@ -2,7 +2,9 @@
namespace App\Exceptions; namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Throwable; use Throwable;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
@ -27,4 +29,33 @@ class Handler extends ExceptionHandler
// //
}); });
} }
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Throwable $e
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Throwable
*/
public function render($request, Throwable $exception)
{
if ($request->expectsJson()) {
}
return $this->prepareJsonResponse($request, $exception);
return parent::render($request, $exception);
}
protected function prepareJsonResponse($request, Throwable $exception)
{
return new JsonResponse(
[
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
],
$this->isHttpException($exception) ? $exception->getStatusCode() : Response::HTTP_INTERNAL_SERVER_ERROR
);
}
} }

6
app/Helpers/Helper.php Normal file
View File

@ -0,0 +1,6 @@
<?php
function hello()
{
return 'hello';
}

View File

@ -3,15 +3,40 @@
namespace App\Http\Middleware; namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware; use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Response;
class Authenticate extends Middleware class Authenticate extends Middleware
{ {
/** /**
* Get the path the user should be redirected to when they are not authenticated. * Handle an unauthenticated user.
*
* @param \Illuminate\Http\Request $request
* @param array $guards
* @return void
*
* @throws \Illuminate\Http\Exceptions\HttpResponseException
*/ */
protected function redirectTo(Request $request): ?string protected function unauthenticated($request, array $guards)
{ {
return $request->expectsJson() ? null : route('login'); throw new HttpResponseException(
Response::json([
'message' => 'Unauthenticated.'
], 401)
);
}
/**
* Handle an unauthenticated user.
*
* @param \Illuminate\Http\Request $request
* @return void
*
* @throws \Illuminate\Http\Exceptions\HttpResponseException
*/
public function responseUnauthenticated($request)
{
return $this->unauthenticated($request, []);
} }
} }

View File

@ -7,8 +7,9 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens; use Laravel\Sanctum\HasApiTokens;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable class User extends Authenticatable implements JWTSubject
{ {
use HasApiTokens, HasFactory, Notifiable; use HasApiTokens, HasFactory, Notifiable;
@ -42,4 +43,24 @@ class User extends Authenticatable
'email_verified_at' => 'datetime', 'email_verified_at' => 'datetime',
'password' => 'hashed', 'password' => 'hashed',
]; ];
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
} }

View File

@ -168,6 +168,7 @@ return [
// App\Providers\BroadcastServiceProvider::class, // App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class, App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
])->toArray(), ])->toArray(),
/* /*

View File

@ -40,6 +40,10 @@ return [
'driver' => 'session', 'driver' => 'session',
'provider' => 'users', 'provider' => 'users',
], ],
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
], ],
/* /*

301
config/jwt.php Normal file
View File

@ -0,0 +1,301 @@
<?php
/*
* This file is part of jwt-auth.
*
* (c) Sean Tymon <tymon148@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
return [
/*
|--------------------------------------------------------------------------
| JWT Authentication Secret
|--------------------------------------------------------------------------
|
| Don't forget to set this in your .env file, as it will be used to sign
| your tokens. A helper command is provided for this:
| `php artisan jwt:secret`
|
| Note: This will be used for Symmetric algorithms only (HMAC),
| since RSA and ECDSA use a private/public key combo (See below).
|
*/
'secret' => env('JWT_SECRET'),
/*
|--------------------------------------------------------------------------
| JWT Authentication Keys
|--------------------------------------------------------------------------
|
| The algorithm you are using, will determine whether your tokens are
| signed with a random string (defined in `JWT_SECRET`) or using the
| following public & private keys.
|
| Symmetric Algorithms:
| HS256, HS384 & HS512 will use `JWT_SECRET`.
|
| Asymmetric Algorithms:
| RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below.
|
*/
'keys' => [
/*
|--------------------------------------------------------------------------
| Public Key
|--------------------------------------------------------------------------
|
| A path or resource to your public key.
|
| E.g. 'file://path/to/public/key'
|
*/
'public' => env('JWT_PUBLIC_KEY'),
/*
|--------------------------------------------------------------------------
| Private Key
|--------------------------------------------------------------------------
|
| A path or resource to your private key.
|
| E.g. 'file://path/to/private/key'
|
*/
'private' => env('JWT_PRIVATE_KEY'),
/*
|--------------------------------------------------------------------------
| Passphrase
|--------------------------------------------------------------------------
|
| The passphrase for your private key. Can be null if none set.
|
*/
'passphrase' => env('JWT_PASSPHRASE'),
],
/*
|--------------------------------------------------------------------------
| JWT time to live
|--------------------------------------------------------------------------
|
| Specify the length of time (in minutes) that the token will be valid for.
| Defaults to 1 hour.
|
| You can also set this to null, to yield a never expiring token.
| Some people may want this behaviour for e.g. a mobile app.
| This is not particularly recommended, so make sure you have appropriate
| systems in place to revoke the token if necessary.
| Notice: If you set this to null you should remove 'exp' element from 'required_claims' list.
|
*/
'ttl' => env('JWT_TTL', 60),
/*
|--------------------------------------------------------------------------
| Refresh time to live
|--------------------------------------------------------------------------
|
| Specify the length of time (in minutes) that the token can be refreshed
| within. I.E. The user can refresh their token within a 2 week window of
| the original token being created until they must re-authenticate.
| Defaults to 2 weeks.
|
| You can also set this to null, to yield an infinite refresh time.
| Some may want this instead of never expiring tokens for e.g. a mobile app.
| This is not particularly recommended, so make sure you have appropriate
| systems in place to revoke the token if necessary.
|
*/
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
/*
|--------------------------------------------------------------------------
| JWT hashing algorithm
|--------------------------------------------------------------------------
|
| Specify the hashing algorithm that will be used to sign the token.
|
*/
'algo' => env('JWT_ALGO', Tymon\JWTAuth\Providers\JWT\Provider::ALGO_HS256),
/*
|--------------------------------------------------------------------------
| Required Claims
|--------------------------------------------------------------------------
|
| Specify the required claims that must exist in any token.
| A TokenInvalidException will be thrown if any of these claims are not
| present in the payload.
|
*/
'required_claims' => [
'iss',
'iat',
'exp',
'nbf',
'sub',
'jti',
],
/*
|--------------------------------------------------------------------------
| Persistent Claims
|--------------------------------------------------------------------------
|
| Specify the claim keys to be persisted when refreshing a token.
| `sub` and `iat` will automatically be persisted, in
| addition to the these claims.
|
| Note: If a claim does not exist then it will be ignored.
|
*/
'persistent_claims' => [
// 'foo',
// 'bar',
],
/*
|--------------------------------------------------------------------------
| Lock Subject
|--------------------------------------------------------------------------
|
| This will determine whether a `prv` claim is automatically added to
| the token. The purpose of this is to ensure that if you have multiple
| authentication models e.g. `App\User` & `App\OtherPerson`, then we
| should prevent one authentication request from impersonating another,
| if 2 tokens happen to have the same id across the 2 different models.
|
| Under specific circumstances, you may want to disable this behaviour
| e.g. if you only have one authentication model, then you would save
| a little on token size.
|
*/
'lock_subject' => true,
/*
|--------------------------------------------------------------------------
| Leeway
|--------------------------------------------------------------------------
|
| This property gives the jwt timestamp claims some "leeway".
| Meaning that if you have any unavoidable slight clock skew on
| any of your servers then this will afford you some level of cushioning.
|
| This applies to the claims `iat`, `nbf` and `exp`.
|
| Specify in seconds - only if you know you need it.
|
*/
'leeway' => env('JWT_LEEWAY', 0),
/*
|--------------------------------------------------------------------------
| Blacklist Enabled
|--------------------------------------------------------------------------
|
| In order to invalidate tokens, you must have the blacklist enabled.
| If you do not want or need this functionality, then set this to false.
|
*/
'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),
/*
| -------------------------------------------------------------------------
| Blacklist Grace Period
| -------------------------------------------------------------------------
|
| When multiple concurrent requests are made with the same JWT,
| it is possible that some of them fail, due to token regeneration
| on every request.
|
| Set grace period in seconds to prevent parallel request failure.
|
*/
'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0),
/*
|--------------------------------------------------------------------------
| Cookies encryption
|--------------------------------------------------------------------------
|
| By default Laravel encrypt cookies for security reason.
| If you decide to not decrypt cookies, you will have to configure Laravel
| to not encrypt your cookie token by adding its name into the $except
| array available in the middleware "EncryptCookies" provided by Laravel.
| see https://laravel.com/docs/master/responses#cookies-and-encryption
| for details.
|
| Set it to true if you want to decrypt cookies.
|
*/
'decrypt_cookies' => false,
/*
|--------------------------------------------------------------------------
| Providers
|--------------------------------------------------------------------------
|
| Specify the various providers used throughout the package.
|
*/
'providers' => [
/*
|--------------------------------------------------------------------------
| JWT Provider
|--------------------------------------------------------------------------
|
| Specify the provider that is used to create and decode the tokens.
|
*/
'jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class,
/*
|--------------------------------------------------------------------------
| Authentication Provider
|--------------------------------------------------------------------------
|
| Specify the provider that is used to authenticate users.
|
*/
'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
/*
|--------------------------------------------------------------------------
| Storage Provider
|--------------------------------------------------------------------------
|
| Specify the provider that is used to store tokens in the blacklist.
|
*/
'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,
],
];

285
config/modules.php Normal file
View File

@ -0,0 +1,285 @@
<?php
use Nwidart\Modules\Activators\FileActivator;
use Nwidart\Modules\Commands;
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'],
'vite' => ['LOWER_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',
],
],
'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'),
/*
|--------------------------------------------------------------------------
| Generator path
|--------------------------------------------------------------------------
| Customise the paths where the folders will be generated.
| Set the generate's key to false to not generate that folder
*/
'generator' => [
'config' => ['path' => 'config', 'generate' => true],
'command' => ['path' => 'app/Console', 'generate' => false],
'channels' => ['path' => 'app/Broadcasting', 'generate' => false],
'migration' => ['path' => 'database/migrations', 'generate' => true],
'seeder' => [
'path' => 'database/seeders',
'namespace' => 'database/seeders',
'generate' => true,
],
'factory' => ['path' => 'database/factories', 'generate' => true],
'model' => ['path' => 'app/Models', 'generate' => true],
'observer' => ['path' => 'app/Observers', 'generate' => false],
'routes' => ['path' => 'routes', 'generate' => true],
'controller' => ['path' => 'app/Http/Controllers', 'generate' => true],
'filter' => ['path' => 'app/Http/Middleware', 'generate' => true],
'request' => ['path' => 'app/Http/Requests', 'generate' => true],
'provider' => ['path' => 'app/Providers', 'generate' => true],
'assets' => ['path' => 'resources/assets', 'generate' => true],
'lang' => ['path' => 'lang', 'generate' => true],
'views' => ['path' => 'resources/views', 'generate' => true],
'test' => ['path' => 'tests/Unit', 'generate' => true],
'test-feature' => ['path' => 'tests/Feature', 'generate' => true],
'repository' => ['path' => 'app/Repositories', 'generate' => false],
'event' => ['path' => 'app/Events', 'generate' => false],
'listener' => ['path' => 'app/Listeners', 'generate' => false],
'policies' => ['path' => 'app/Policies', 'generate' => false],
'rules' => ['path' => 'app/Rules', 'generate' => false],
'jobs' => ['path' => 'app/Jobs', 'generate' => false],
'emails' => ['path' => 'app/Emails', 'generate' => false],
'notifications' => ['path' => 'app/Notifications', 'generate' => false],
'resource' => ['path' => 'app/Resources', 'generate' => false],
'component-view' => ['path' => 'resources/views/components', 'generate' => false],
'component-class' => ['path' => 'app/View/Components', 'generate' => false],
],
],
/*
|--------------------------------------------------------------------------
| Package commands
|--------------------------------------------------------------------------
|
| Here you can define which commands will be visible and used in your
| application. If for example, you don't use some of the commands provided
| you can simply comment them out.
|
*/
'commands' => [
Commands\CommandMakeCommand::class,
Commands\ComponentClassMakeCommand::class,
Commands\ComponentViewMakeCommand::class,
Commands\ControllerMakeCommand::class,
Commands\ChannelMakeCommand::class,
Commands\DisableCommand::class,
Commands\DumpCommand::class,
Commands\EnableCommand::class,
Commands\EventMakeCommand::class,
Commands\FactoryMakeCommand::class,
Commands\JobMakeCommand::class,
Commands\ListenerMakeCommand::class,
Commands\MailMakeCommand::class,
Commands\MiddlewareMakeCommand::class,
Commands\NotificationMakeCommand::class,
Commands\ObserverMakeCommand::class,
Commands\PolicyMakeCommand::class,
Commands\ProviderMakeCommand::class,
Commands\InstallCommand::class,
Commands\LaravelModulesV6Migrator::class,
Commands\ListCommand::class,
Commands\ModuleDeleteCommand::class,
Commands\ModuleMakeCommand::class,
Commands\MigrateCommand::class,
Commands\MigrateFreshCommand::class,
Commands\MigrateRefreshCommand::class,
Commands\MigrateResetCommand::class,
Commands\MigrateRollbackCommand::class,
Commands\MigrateStatusCommand::class,
Commands\MigrationMakeCommand::class,
Commands\ModelMakeCommand::class,
Commands\ResourceMakeCommand::class,
Commands\RequestMakeCommand::class,
Commands\RuleMakeCommand::class,
Commands\RouteProviderMakeCommand::class,
Commands\PublishCommand::class,
Commands\PublishConfigurationCommand::class,
Commands\PublishMigrationCommand::class,
Commands\PublishTranslationCommand::class,
Commands\SeedCommand::class,
Commands\SeedMakeCommand::class,
Commands\SetupCommand::class,
Commands\TestMakeCommand::class,
Commands\UnUseCommand::class,
Commands\UpdateCommand::class,
Commands\UseCommand::class,
],
/*
|--------------------------------------------------------------------------
| 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' => 'nwidart',
'author' => [
'name' => 'Nicolas Widart',
'email' => 'n.widart@gmail.com',
],
'composer-output' => false,
],
/*
|--------------------------------------------------------------------------
| Caching
|--------------------------------------------------------------------------
|
| Here is the config for setting up the caching feature.
|
*/
'cache' => [
'enabled' => false,
'driver' => 'file',
'key' => 'laravel-modules',
'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
*
* Note: boot not compatible with asgardcms
*
* @example boot|register
*/
'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

@ -12,11 +12,9 @@ class DatabaseSeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
// \App\Models\User::factory(10)->create(); $this->call([
UserSeeder::class,
// \App\Models\User::factory()->create([ // Add other seeders if necessary
// 'name' => 'Test User', ]);
// 'email' => 'test@example.com',
// ]);
} }
} }

View File

@ -0,0 +1,26 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$user = new \App\Models\User;
if (!$user->find(['email' => 'admin@apactech.io'])) {
$user->factory()->createOne([
'name' => 'admin',
'email' => 'admin@apactech.io',
'password' => bcrypt('admin123')
]);
}
$user->factory(10)->create();
dump($user->get()->toArray());
}
}

View File

View File

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,31 @@
{
"name": "$VENDOR$/$LOWER_NAME$",
"description": "",
"authors": [
{
"name": "$AUTHOR_NAME$",
"email": "$AUTHOR_EMAIL$"
}
],
"extra": {
"laravel": {
"providers": [],
"aliases": {
}
}
},
"autoload": {
"psr-4": {
"$MODULE_NAMESPACE$\\$STUDLY_NAME$\\": "",
"$MODULE_NAMESPACE$\\$STUDLY_NAME$\\App\\": "app/",
"$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,62 @@
<?php
namespace $CLASS_NAMESPACE$;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class $CLASS$ extends Controller
{
public array $data = [];
/**
* Display a listing of the resource.
*/
public function index(): JsonResponse
{
//
return response()->json($this->data);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request): JsonResponse
{
//
return response()->json($this->data);
}
/**
* Show the specified resource.
*/
public function show($id): JsonResponse
{
//
return response()->json($this->data);
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id): JsonResponse
{
//
return response()->json($this->data);
}
/**
* Remove the specified resource from storage.
*/
public function destroy($id): JsonResponse
{
//
return response()->json($this->data);
}
}

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,26 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Queue\SerializesModels;
class $CLASS$
{
use SerializesModels;
/**
* Create a new event instance.
*/
public function __construct()
{
//
}
/**
* Get the channels the event should be broadcast on.
*/
public function broadcastOn(): array
{
return [];
}
}

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,27 @@
<?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;
// return auth()->user()->can('users.create');
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Http\Resources\Json\ResourceCollection;
class $CLASS$ extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*/
public function toArray($request): array
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Http\Resources\Json\JsonResource;
class $CLASS$ extends JsonResource
{
/**
* Transform the resource into an array.
*/
public function toArray($request): array
{
return parent::toArray($request);
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class $CLASS$ extends ServiceProvider
{
/**
* The module namespace to assume when generating URLs to actions.
*/
protected string $moduleNamespace = '$MODULE_NAMESPACE$\$MODULE$\$CONTROLLER_NAMESPACE$';
/**
* Called before routes are registered.
*
* Register any model bindings or pattern based filters.
*/
public function boot(): void
{
parent::boot();
}
/**
* Define the routes for the application.
*/
public function map(): void
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*/
protected function mapWebRoutes(): void
{
Route::middleware('web')
->namespace($this->moduleNamespace)
->group(module_path('$MODULE$', '$WEB_ROUTES_PATH$'));
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*/
protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
->namespace($this->moduleNamespace)
->group(module_path('$MODULE$', '$API_ROUTES_PATH$'));
}
}

View File

@ -0,0 +1,19 @@
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware(['auth:sanctum'])->prefix('v1')->name('api.')->group(function () {
Route::get('$LOWER_NAME$', fn (Request $request) => $request->user())->name('$LOWER_NAME$');
});

View File

@ -0,0 +1,19 @@
<?php
use Illuminate\Support\Facades\Route;
use $MODULE_NAMESPACE$\$STUDLY_NAME$\$CONTROLLER_NAMESPACE$\$STUDLY_NAME$Controller;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::group([], function () {
Route::resource('$LOWER_NAME$', $STUDLY_NAME$Controller::class)->names('$LOWER_NAME$');
});

View File

@ -0,0 +1,22 @@
<?php
namespace $NAMESPACE$;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class $CLASS$ implements ValidationRule
{
/**
* Indicates whether the rule should be implicit.
*/
public bool $implicit = true;
/**
* Run the validation rule.
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
//
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace $NAMESPACE$;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class $CLASS$ implements ValidationRule
{
/**
* Run the validation rule.
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
//
}
}

View File

@ -0,0 +1,5 @@
<?php
return [
'name' => '$STUDLY_NAME$',
];

View File

@ -0,0 +1,114 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class $CLASS$ extends ServiceProvider
{
protected string $moduleName = '$MODULE$';
protected string $moduleNameLower = '$LOWER_NAME$';
/**
* Boot the application events.
*/
public function boot(): void
{
$this->registerCommands();
$this->registerCommandSchedules();
$this->registerTranslations();
$this->registerConfig();
$this->registerViews();
$this->loadMigrationsFrom(module_path($this->moduleName, '$MIGRATIONS_PATH$'));
}
/**
* Register the service provider.
*/
public function register(): void
{
$this->app->register(RouteServiceProvider::class);
}
/**
* Register commands in the format of Command::class
*/
protected function registerCommands(): void
{
// $this->commands([]);
}
/**
* Register command Schedules.
*/
protected function registerCommandSchedules(): void
{
// $this->app->booted(function () {
// $schedule = $this->app->make(Schedule::class);
// $schedule->command('inspire')->hourly();
// });
}
/**
* Register translations.
*/
public function registerTranslations(): void
{
$langPath = resource_path('lang/modules/'.$this->moduleNameLower);
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
$this->loadJsonTranslationsFrom($langPath);
} else {
$this->loadTranslationsFrom(module_path($this->moduleName, '$PATH_LANG$'), $this->moduleNameLower);
$this->loadJsonTranslationsFrom(module_path($this->moduleName, '$PATH_LANG$'));
}
}
/**
* Register config.
*/
protected function registerConfig(): void
{
$this->publishes([module_path($this->moduleName, '$PATH_CONFIG$/config.php') => config_path($this->moduleNameLower.'.php')], 'config');
$this->mergeConfigFrom(module_path($this->moduleName, '$PATH_CONFIG$/config.php'), $this->moduleNameLower);
}
/**
* Register views.
*/
public function registerViews(): void
{
$viewPath = resource_path('views/modules/'.$this->moduleNameLower);
$sourcePath = module_path($this->moduleName, '$PATH_VIEWS$');
$this->publishes([$sourcePath => $viewPath], ['views', $this->moduleNameLower.'-module-views']);
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
$componentNamespace = str_replace('/', '\\', config('modules.namespace').'\\'.$this->moduleName.'\\'.config('modules.paths.generator.component-class.path'));
Blade::componentNamespace($componentNamespace, $this->moduleNameLower);
}
/**
* Get the services provided by the provider.
*/
public function provides(): array
{
return [];
}
private function getPublishableViewPaths(): array
{
$paths = [];
foreach (config('view.paths') as $path) {
if (is_dir($path.'/modules/'.$this->moduleNameLower)) {
$paths[] = $path.'/modules/'.$this->moduleNameLower;
}
}
return $paths;
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace $NAMESPACE$;
use Illuminate\Database\Seeder;
class $NAME$ extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// $this->call([]);
}
}

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 unit test example.
*
* @return void
*/
public function testExample()
{
$this->assertTrue(true);
}
}

View File

@ -0,0 +1,7 @@
@extends('$LOWER_NAME$::layouts.master')
@section('content')
<h1>Hello World</h1>
<p>Module: {!! config('$LOWER_NAME$.name') !!}</p>
@endsection

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>$STUDLY_NAME$ Module - {{ config('app.name', 'Laravel') }}</title>
<meta name="description" content="{{ $description ?? '' }}">
<meta name="keywords" content="{{ $keywords ?? '' }}">
<meta name="author" content="{{ $author ?? '' }}">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
{{-- Vite CSS --}}
{{-- {{ module_vite('build-$LOWER_NAME$', 'resources/assets/sass/app.scss') }} --}}
</head>
<body>
@yield('content')
{{-- Vite JS --}}
{{-- {{ module_vite('build-$LOWER_NAME$', 'resources/assets/js/app.js') }} --}}
</body>

View File

@ -0,0 +1,26 @@
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
build: {
outDir: '../../public/build-$LOWER_NAME$',
emptyOutDir: true,
manifest: true,
},
plugins: [
laravel({
publicDirectory: '../../public',
buildDirectory: 'build-$LOWER_NAME$',
input: [
__dirname + '/resources/assets/sass/app.scss',
__dirname + '/resources/assets/js/app.js'
],
refresh: true,
}),
],
});
//export const paths = [
// 'Modules/$STUDLY_NAME$/resources/assets/sass/app.scss',
// 'Modules/$STUDLY_NAME$/resources/assets/js/app.js',
//];