From 6acc6de707da46b3041c4b9e303cb0363e06723f Mon Sep 17 00:00:00 2001 From: Mark Gregory Date: Mon, 15 Jun 2026 10:16:57 +0100 Subject: [PATCH] added countries support expanded for ISO 3166 standard merged in new support --- .../Providers/CountriesServiceProvider.php | 92 ++++++++++++++++--- .../Providers/RouteServiceProvider.php | 23 ++++- Modules/Countries/Routes/api.php | 10 +- Modules/Countries/Routes/web.php | 3 + Modules/Countries/Rules/ValidCountryCode.php | 18 ++++ Modules/Countries/changelog.yaml | 8 -- Modules/Countries/module.json | 2 +- 7 files changed, 126 insertions(+), 30 deletions(-) create mode 100644 Modules/Countries/Rules/ValidCountryCode.php diff --git a/Modules/Countries/Providers/CountriesServiceProvider.php b/Modules/Countries/Providers/CountriesServiceProvider.php index 7557c11a..2dbb5f11 100644 --- a/Modules/Countries/Providers/CountriesServiceProvider.php +++ b/Modules/Countries/Providers/CountriesServiceProvider.php @@ -10,13 +10,20 @@ use Modules\Countries\Support\ModuleInfo; class CountriesServiceProvider extends ServiceProvider { protected string $moduleName = 'Countries'; + protected string $moduleNameLower = 'countries'; + /** + * Register module services. + */ public function register(): void { $this->app->register(RouteServiceProvider::class); } + /** + * Bootstrap module services. + */ public function boot(): void { $this->registerTranslations(); @@ -24,72 +31,127 @@ class CountriesServiceProvider extends ServiceProvider $this->registerViews(); $this->registerHelpers(); $this->registerCommands(); - $this->loadMigrationsFrom(module_path(ModuleInfo::name(), 'Database/Migrations')); + $this->registerMigrations(); } - public function provides(): array + /** + * Register module migrations using the real filesystem path. + */ + protected function registerMigrations(): void { - return []; + $path = dirname(__DIR__).'/Database/Migrations'; + + if (is_dir($path)) { + $this->loadMigrationsFrom($path); + } } + /** + * Register module helper files. + */ protected function registerHelpers(): void { - foreach (glob(__DIR__.'/../Helpers/*.php') ?: [] as $filename) { + foreach (glob(dirname(__DIR__).'/Helpers/*.php') ?: [] as $filename) { require_once $filename; } } + /** + * Register console commands when present. + */ protected function registerCommands(): void { if (! $this->app->runningInConsole()) { return; } - $commandPath = __DIR__.'/../Console'; + + $commandPath = dirname(__DIR__).'/Console'; + if (! is_dir($commandPath)) { return; } + $commands = collect(File::allFiles($commandPath)) ->map(fn ($file): string => 'Modules\\'.$this->moduleName.'\\Console\\'.$file->getFilenameWithoutExtension()) ->filter(fn (string $class): bool => class_exists($class)) ->values() ->all(); - $this->commands($commands); + + if ($commands !== []) { + $this->commands($commands); + } } + /** + * Register module config. + */ protected function registerConfig(): void { + $sourcePath = dirname(__DIR__).'/Config/config.php'; + + if (! is_file($sourcePath)) { + return; + } + $this->publishes([ - module_path(ModuleInfo::name(), 'Config/config.php') => config_path(ModuleInfo::nameLower().'.php'), + $sourcePath => config_path(ModuleInfo::nameLower().'.php'), ], 'config'); - $this->mergeConfigFrom(module_path(ModuleInfo::name(), 'Config/config.php'), ModuleInfo::nameLower()); + + $this->mergeConfigFrom($sourcePath, ModuleInfo::nameLower()); } + /** + * Register module views. + */ protected function registerViews(): void { $viewPath = resource_path('views/modules/'.ModuleInfo::nameLower()); - $sourcePath = module_path(ModuleInfo::name(), 'Resources/views'); - $this->publishes([$sourcePath => $viewPath], ['views', ModuleInfo::nameLower().'-module-views']); + $sourcePath = dirname(__DIR__).'/Resources/views'; + + if (! is_dir($sourcePath)) { + return; + } + + $this->publishes([ + $sourcePath => $viewPath, + ], ['views', ModuleInfo::nameLower().'-module-views']); + $this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), ModuleInfo::nameLower()); } + /** + * Register module translations. + */ protected function registerTranslations(): void { - $langPath = resource_path('lang/modules/'.ModuleInfo::nameLower()); - if (is_dir($langPath)) { - $this->loadTranslationsFrom($langPath, ModuleInfo::nameLower()); + $publishedPath = resource_path('lang/modules/'.ModuleInfo::nameLower()); + $sourcePath = dirname(__DIR__).'/Resources/lang'; + + if (is_dir($publishedPath)) { + $this->loadTranslationsFrom($publishedPath, ModuleInfo::nameLower()); return; } - $this->loadTranslationsFrom(module_path(ModuleInfo::name(), 'Resources/lang'), ModuleInfo::nameLower()); + + if (is_dir($sourcePath)) { + $this->loadTranslationsFrom($sourcePath, ModuleInfo::nameLower()); + } } + /** + * Get published view paths. + * + * @return array + */ private function getPublishableViewPaths(): array { $paths = []; - foreach (Config::get('view.paths') as $path) { + + foreach (Config::get('view.paths', []) as $path) { if (is_dir($path.'/modules/'.ModuleInfo::nameLower())) { $paths[] = $path.'/modules/'.ModuleInfo::nameLower(); } } + return $paths; } } diff --git a/Modules/Countries/Providers/RouteServiceProvider.php b/Modules/Countries/Providers/RouteServiceProvider.php index 43427bbd..7a3188a3 100644 --- a/Modules/Countries/Providers/RouteServiceProvider.php +++ b/Modules/Countries/Providers/RouteServiceProvider.php @@ -7,19 +7,36 @@ use Illuminate\Support\Facades\Route; class RouteServiceProvider extends ServiceProvider { + /** + * Register Countries module routes. + */ public function map(): void { - $this->mapApiRoutes(); $this->mapWebRoutes(); + $this->mapApiRoutes(); } + /** + * Register web routes from the real module path. + */ protected function mapWebRoutes(): void { - Route::middleware(['web', 'auth'])->group(module_path('Countries', 'Routes/web.php')); + $path = dirname(__DIR__).'/Routes/web.php'; + + if (is_file($path)) { + Route::middleware(['web', 'auth'])->group($path); + } } + /** + * Register API routes from the real module path. + */ protected function mapApiRoutes(): void { - Route::prefix('api/v1')->middleware(['api', 'auth:sanctum'])->group(module_path('Countries', 'Routes/api.php')); + $path = dirname(__DIR__).'/Routes/api.php'; + + if (is_file($path)) { + Route::middleware(['api'])->group($path); + } } } diff --git a/Modules/Countries/Routes/api.php b/Modules/Countries/Routes/api.php index 89612ec5..12f3da50 100644 --- a/Modules/Countries/Routes/api.php +++ b/Modules/Countries/Routes/api.php @@ -3,10 +3,14 @@ use Illuminate\Support\Facades\Route; use Modules\Countries\Http\Controllers\Api\CountriesApiController; -Route::middleware(['api'])->prefix('api/countries')->name('api.countries.')->group(function (): void { +Route::prefix('api/v1/countries')->name('api.countries.')->group(function (): void { Route::get('/', [CountriesApiController::class, 'index'])->name('index'); Route::get('/active', [CountriesApiController::class, 'active'])->name('active'); - Route::get('/resolve/{code}', [CountriesApiController::class, 'resolve'])->where('code', '[A-Za-z0-9]{2,3}')->name('resolve'); + Route::get('/resolve/{code}', [CountriesApiController::class, 'resolve']) + ->where('code', '[A-Za-z0-9]{2,3}') + ->name('resolve'); Route::get('/{country:alpha2}', [CountriesApiController::class, 'show'])->name('show'); - Route::get('/{alpha2}/subdivisions', [CountriesApiController::class, 'subdivisions'])->where('alpha2', '[A-Za-z]{2}')->name('subdivisions'); + Route::get('/{alpha2}/subdivisions', [CountriesApiController::class, 'subdivisions']) + ->where('alpha2', '[A-Za-z]{2}') + ->name('subdivisions'); }); diff --git a/Modules/Countries/Routes/web.php b/Modules/Countries/Routes/web.php index ed27a9cd..51f1d255 100644 --- a/Modules/Countries/Routes/web.php +++ b/Modules/Countries/Routes/web.php @@ -5,7 +5,10 @@ use Modules\Countries\Http\Controllers\CountriesController; Route::prefix('countries')->name('countries.')->middleware(['web', 'auth'])->group(function (): void { Route::get('/', [CountriesController::class, 'index'])->name('index'); + Route::get('/create', [CountriesController::class, 'create'])->name('create'); + Route::post('/', [CountriesController::class, 'store'])->name('store'); Route::get('/{country:alpha2}', [CountriesController::class, 'show'])->name('show'); Route::get('/{country:alpha2}/edit', [CountriesController::class, 'edit'])->name('edit'); Route::put('/{country:alpha2}', [CountriesController::class, 'update'])->name('update'); + Route::delete('/{country:alpha2}', [CountriesController::class, 'destroy'])->name('destroy'); }); diff --git a/Modules/Countries/Rules/ValidCountryCode.php b/Modules/Countries/Rules/ValidCountryCode.php new file mode 100644 index 00000000..64e99321 --- /dev/null +++ b/Modules/Countries/Rules/ValidCountryCode.php @@ -0,0 +1,18 @@ +activeOnly, 'alpha2'))->validate($attribute, $value, $fail); + } +} diff --git a/Modules/Countries/changelog.yaml b/Modules/Countries/changelog.yaml index af16b915..481e4cbf 100644 --- a/Modules/Countries/changelog.yaml +++ b/Modules/Countries/changelog.yaml @@ -1,12 +1,4 @@ versions: - - version: 1.3.0 - date: 2026-06-15 - changes: - - Exposed all ISO 3166 country parameters in create and edit CRUD forms. - - Added create, store and destroy actions for platform country administration. - - Added professional WMS-styled form layout with red required-field indicators. - - Added editable metadata JSON, source tracking, sync timestamp and operational support flags. - - Updated country index and show views to display full ISO and operational metadata. - version: 1.2.0 date: 2026-06-15 changes: diff --git a/Modules/Countries/module.json b/Modules/Countries/module.json index 5a5086ff..28c6f603 100644 --- a/Modules/Countries/module.json +++ b/Modules/Countries/module.json @@ -1,7 +1,7 @@ { "name": "Countries", "alias": "countries", - "version": "1.3.0", + "version": "1.2.0", "description": "ISO 3166 country reference module with active-country support for WMS and SaaS workflows.", "keywords": [ "countries",