diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..da7b93b
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,87 @@
+name: Tests
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ branches: [master]
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ php: [8.1, 8.2, 8.3, 8.4]
+ laravel: [10.*, 11.*, 12.*]
+ exclude:
+ - php: 8.1
+ laravel: 11.*
+ - php: 8.1
+ laravel: 12.*
+
+ name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php }}
+ extensions: dom, curl, libxml, mbstring, zip, json
+ coverage: none
+
+ - name: Install dependencies
+ run: |
+ composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
+ composer update --prefer-dist --no-interaction
+
+ - name: Run tests
+ run: composer test
+
+ static-analysis:
+ runs-on: ubuntu-latest
+
+ name: Static Analysis
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 8.3
+ extensions: dom, curl, libxml, mbstring, zip, json
+ coverage: none
+
+ - name: Install dependencies
+ run: composer update --prefer-dist --no-interaction
+
+ - name: Run PHPStan
+ run: composer analyse
+
+ code-style:
+ runs-on: ubuntu-latest
+
+ name: Code Style
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 8.3
+ extensions: dom, curl, libxml, mbstring, zip, json
+ coverage: none
+
+ - name: Install dependencies
+ run: composer update --prefer-dist --no-interaction
+
+ - name: Check code style
+ run: ./vendor/bin/php-cs-fixer fix --dry-run --diff --allow-risky=yes
diff --git a/.gitignore b/.gitignore
index 6c6cff4..a7c1796 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,7 @@ build
coverage
.env
.env.backup
-.php_cs.cache
+.php-cs-fixer.cache
.phpunit.result.cache
.phpunit.cache
.phpstorm.meta.php
diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
new file mode 100644
index 0000000..3012836
--- /dev/null
+++ b/.php-cs-fixer.dist.php
@@ -0,0 +1,39 @@
+in([
+ __DIR__ . '/src',
+ __DIR__ . '/tests',
+ ])
+ ->name('*.php')
+ ->notName('*.blade.php')
+ ->exclude([
+ '__snapshots__',
+ '.pest',
+ ])
+ ->ignoreDotFiles(true)
+ ->ignoreVCS(true);
+
+return (new PhpCsFixer\Config())
+ ->setRules([
+ '@PSR12' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'ordered_imports' => ['sort_algorithm' => 'alpha'],
+ 'no_unused_imports' => true,
+ 'not_operator_with_successor_space' => true,
+ 'trailing_comma_in_multiline' => true,
+ 'phpdoc_scalar' => true,
+ 'unary_operator_spaces' => true,
+ 'binary_operator_spaces' => true,
+ 'blank_line_before_statement' => [
+ 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'],
+ ],
+ 'phpdoc_single_line_var_spacing' => true,
+ 'phpdoc_var_without_name' => true,
+ 'method_argument_space' => [
+ 'on_multiline' => 'ensure_fully_multiline',
+ 'keep_multiple_spaces_after_comma' => true,
+ ],
+ 'single_trait_insert_per_statement' => true,
+ ])
+ ->setFinder($finder);
diff --git a/README.md b/README.md
index bc2d753..83b500f 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,871 @@
# Laraneat Modules
-This package is reworked version of [Laravel modules](https://github.com/nWidart/laravel-modules/).
+A Laravel package that provides a powerful modular architecture system for organizing large-scale applications into self-contained, reusable modules.
-- The code is completely rewritten in PHP 8
-- Removed dead unused code
-- Significantly improved performance by refactoring the caching system
-- Dropped Lumen support
-- Rewritten code generators, added many new component generators related to [Laraneat framework](https://github.com/laraneat/laraneat)
+## Table of Contents
-Developed as part of the [Laraneat framework](https://github.com/laraneat/laraneat)
+- [Overview](#overview)
+- [Performance Comparison](#performance-comparison-with-nwidartlaravel-modules)
+- [Architecture Diagram](#architecture-diagram)
+- [Installation](#installation)
+- [Quick Start](#quick-start)
+- [Module Structure](#module-structure)
+- [Core Concepts](#core-concepts)
+- [Configuration](#configuration)
+- [Artisan Commands](#artisan-commands)
+- [Component Types](#component-types)
+- [Module Presets](#module-presets)
+- [Best Practices](#best-practices)
-Currently under development.
+## Overview
+
+Laraneat Modules helps you build maintainable, scalable Laravel applications. Inspired by the [Porto SAP (Software Architectural Pattern)](https://github.com/Mahmoudz/Porto), it encourages organizing code by business domains (modules) instead of technical layers.
+
+### Why Modular Architecture?
+
+| Traditional Laravel | Modular Approach |
+|---------------------|------------------|
+| All controllers in `app/Http/Controllers` | Each module has its own controllers |
+| All models in `app/Models` | Each module has its own models |
+| Coupled, hard to maintain | Decoupled, easy to maintain |
+| Difficult to reuse | Easy to extract and reuse |
+| Complex routing | Module-scoped routing |
+
+## Performance Comparison with nWidart/laravel-modules
+
+This package is designed with performance in mind. **With caching enabled, it adds virtually zero overhead** — the cached manifest is a simple PHP array that loads in microseconds, and all core services use lazy loading.
+
+Here's how it compares to the popular [nWidart/laravel-modules](https://github.com/nWidart/laravel-modules):
+
+### Key Differences
+
+| Feature | Laraneat Modules | nWidart/laravel-modules |
+|---------|------------------|-------------------------|
+| **Module manifest** | `composer.json` only | `module.json` + `composer.json` |
+| **Cache type** | Persistent file cache | In-memory only (per request) |
+| **Service providers** | DeferrableProvider (lazy) | Eager loading |
+| **Enable/disable modules** | Not supported | Supported via JSON file |
+| **Architecture pattern** | Domain-driven (Porto-inspired) | Flexible structure |
+
+### Performance Impact
+
+#### Production (with cache enabled)
+
+| Metric | Laraneat | nWidart |
+|--------|----------|---------|
+| File operations (first request) | 1 (cached manifest) | N (module.json × modules) |
+| File operations (subsequent) | 1 | N |
+| Providers loaded | On-demand | All modules |
+
+#### Development (without cache)
+
+Both packages scan the filesystem on each request. However, Laraneat uses `DeferrableProvider`, so the `ModulesRepository` is only instantiated when actually needed.
+
+### Why Laraneat is Faster
+
+1. **Persistent manifest cache** — Module metadata is cached to `bootstrap/cache/laraneat-modules.php`, eliminating filesystem scans in production.
+
+2. **DeferrableProvider** — Core services (`ModulesRepository`, `Composer`, console commands) implement Laravel's `DeferrableProvider` interface, loading only when requested.
+
+3. **Single manifest file** — Uses existing `composer.json` instead of requiring an additional `module.json` per module.
+
+4. **No status file I/O** — No `modules_statuses.json` reads on every request (unlike nWidart's enabled/disabled feature).
+
+### Recommendations
+
+```php
+// config/modules.php - Enable cache in production
+'cache' => [
+ 'enabled' => env('APP_ENV') === 'production',
+],
+```
+
+After deployment:
+```bash
+php artisan module:cache
+```
+
+For development with many modules, consider enabling cache manually to avoid repeated filesystem scans.
+
+## Architecture Diagram
+
+```
+┌─────────────────────────────────────────────────────────────────────────────┐
+│ LARAVEL APPLICATION │
+├─────────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌─────────────────────────────────────────────────────────────────────┐ │
+│ │ ModulesRepository │ │
+│ │ - Discovers modules by scanning configured paths │ │
+│ │ - Manages module manifest (cached in production) │ │
+│ │ - Provides find, filter, delete operations │ │
+│ └──────────────────────────────┬──────────────────────────────────────┘ │
+│ │ │
+│ ┌────────────┼────────────┐ │
+│ │ │ │ │
+│ ▼ ▼ ▼ │
+│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │
+│ │ MODULE: Users │ │ MODULE: Articles │ │ MODULE: Orders │ │
+│ │ │ │ │ │ │ │
+│ │ ┌───────────────┐ │ │ ┌───────────────┐ │ │ ┌───────────────┐ │ │
+│ │ │ composer.json│ │ │ │ composer.json│ │ │ │ composer.json│ │ │
+│ │ │ - providers │ │ │ │ - providers │ │ │ │ - providers │ │ │
+│ │ │ - aliases │ │ │ │ - aliases │ │ │ │ - aliases │ │ │
+│ │ │ - namespace │ │ │ │ - namespace │ │ │ │ - namespace │ │ │
+│ │ └───────────────┘ │ │ └───────────────┘ │ │ └───────────────┘ │ │
+│ │ │ │ │ │ │ │
+│ │ src/ │ │ src/ │ │ src/ │ │
+│ │ ├── Actions/ │ │ ├── Actions/ │ │ ├── Actions/ │ │
+│ │ ├── Models/ │ │ ├── Models/ │ │ ├── Models/ │ │
+│ │ ├── Providers/ │ │ ├── Providers/ │ │ ├── Providers/ │ │
+│ │ └── UI/ │ │ └── UI/ │ │ └── UI/ │ │
+│ │ ├── API/ │ │ ├── API/ │ │ ├── API/ │ │
+│ │ ├── WEB/ │ │ ├── WEB/ │ │ ├── WEB/ │ │
+│ │ └── CLI/ │ │ └── CLI/ │ │ └── CLI/ │ │
+│ │ │ │ │ │ │ │
+│ │ database/ │ │ database/ │ │ database/ │ │
+│ │ └── migrations/ │ │ └── migrations/ │ │ └── migrations/ │ │
+│ │ │ │ │ │ │ │
+│ │ tests/ │ │ tests/ │ │ tests/ │ │
+│ └─────────────────────┘ └─────────────────────┘ └─────────────────────┘ │
+│ │
+└─────────────────────────────────────────────────────────────────────────────┘
+```
+
+### Module Internal Architecture
+
+```
+┌────────────────────────────────────────────────────────────────────────┐
+│ MODULE │
+├────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌──────────────────────────── UI LAYER ────────────────────────────┐ │
+│ │ │ │
+│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
+│ │ │ API │ │ WEB │ │ CLI │ │ │
+│ │ │ Controllers │ │ Controllers │ │ Commands │ │ │
+│ │ │ Requests │ │ Requests │ │ │ │ │
+│ │ │ Resources │ │ Views │ │ │ │ │
+│ │ │ Routes │ │ Routes │ │ │ │ │
+│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
+│ │ │ │ │ │ │
+│ └─────────┼──────────────────┼──────────────────┼──────────────────┘ │
+│ │ │ │ │
+│ └──────────────────┼──────────────────┘ │
+│ ▼ │
+│ ┌────────────────────── DOMAIN LAYER ──────────────────────────────┐ │
+│ │ │ │
+│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
+│ │ │ Actions │ │ DTOs │ │ Events │ │ │
+│ │ │ (Business │ │ (Data │ │ (Domain │ │ │
+│ │ │ Logic) │ │ Transfer) │ │ Events) │ │ │
+│ │ └──────┬──────┘ └─────────────┘ └─────────────┘ │ │
+│ │ │ │ │
+│ │ ▼ │ │
+│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
+│ │ │ Models │ │ Observers │ │ Rules │ │ │
+│ │ │ (Entities) │ │ │ │(Validation) │ │ │
+│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
+│ │ │ │
+│ └───────────────────────────────────────────────────────────────────┘ │
+│ │
+│ ┌─────────────────── INFRASTRUCTURE LAYER ─────────────────────────┐ │
+│ │ │ │
+│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
+│ │ │ Providers │ │ Middleware │ │ Policies │ │ │
+│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
+│ │ │ │
+│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
+│ │ │ Mails │ │Notifications│ │ Jobs │ │ │
+│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
+│ │ │ │
+│ └───────────────────────────────────────────────────────────────────┘ │
+│ │
+│ ┌──────────────────── DATABASE LAYER ──────────────────────────────┐ │
+│ │ │ │
+│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
+│ │ │ Migrations │ │ Seeders │ │ Factories │ │ │
+│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
+│ │ │ │
+│ └───────────────────────────────────────────────────────────────────┘ │
+│ │
+└────────────────────────────────────────────────────────────────────────┘
+```
+
+### Request Flow Through Module
+
+Actions serve as controllers using the `lorisleiva/laravel-actions` package. Each Action has two entry points:
+- `handle()` - Core business logic (can be called from anywhere)
+- `asController()` - HTTP entry point (receives Request, returns Response)
+
+```
+┌──────────┐ ┌───────────┐ ┌────────────┐
+│ HTTP │────▶│ Routes │────▶│ Middleware │
+│ Request │ │ │ │ │
+└──────────┘ └───────────┘ └─────┬──────┘
+ │
+ ┌───────────────────────┘
+ ▼
+┌─────────────────────────────────────────────────────────────────┐
+│ ACTION │
+│ ┌─────────────────────────────────────────────────────────┐ │
+│ │ asController(Request $request) ◀── HTTP Entry │ │
+│ │ │ │ │
+│ │ ├── $request->toDTO() ─────────▶ DTO │ │
+│ │ │ │ │
+│ │ └── $this->handle($dto) │ │
+│ └────────────────────────┬────────────────────────────────┘ │
+│ ▼ │
+│ ┌─────────────────────────────────────────────────────────┐ │
+│ │ handle(DTO $dto) ◀── Business Logic │ │
+│ │ │ │ │
+│ │ └── Model::create($dto->all()) ──▶ Database │ │
+│ └────────────────────────┬────────────────────────────────┘ │
+│ │ │
+└───────────────────────────┼──────────────────────────────────────┘
+ ▼
+ ┌────────────────┐ ┌─────────────┐
+ │ Resource │────▶│ HTTP │
+ │ (Format) │ │ Response │
+ └────────────────┘ └─────────────┘
+```
+
+**Example Action:**
+
+```php
+class CreatePostAction
+{
+ use AsAction;
+
+ // Business logic - can be called from anywhere
+ public function handle(CreatePostDTO $dto): Post
+ {
+ return Post::create($dto->all());
+ }
+
+ // HTTP entry point - acts as controller
+ public function asController(CreatePostRequest $request): JsonResponse
+ {
+ $post = $this->handle($request->toDTO());
+
+ return (new PostResource($post))->created();
+ }
+}
+```
+
+## Installation
+
+```bash
+composer require laraneat/modules
+```
+
+Publish the configuration file:
+
+```bash
+php artisan vendor:publish --provider="Laraneat\Modules\Providers\ModulesServiceProvider"
+```
+
+## Quick Start
+
+### 1. Create Your First Module
+
+```bash
+php artisan module:make Blog
+```
+
+This creates a new module at `modules/blog/` with basic structure.
+
+### 2. Create Module with Full API
+
+```bash
+php artisan module:make Blog --preset=api --entity=Post
+```
+
+This creates a complete REST API module with:
+- Controllers for CRUD operations
+- Request validation classes
+- API resources for JSON responses
+- Database migrations and seeders
+- Complete test suite
+
+### 3. Generate Components
+
+```bash
+# Create a model
+php artisan module:make:model Post app/blog
+
+# Create a controller
+php artisan module:make:controller PostController app/blog --ui=api
+
+# Create a migration
+php artisan module:make:migration create_posts_table app/blog
+
+# Create an action
+php artisan module:make:action CreatePostAction app/blog
+```
+
+### 4. Run Module Migrations
+
+```bash
+php artisan module:migrate
+```
+
+## Module Structure
+
+A complete module follows this structure:
+
+```
+modules/blog/
+├── composer.json # Module package definition
+├── src/
+│ ├── Actions/ # Business logic actions
+│ │ ├── CreatePostAction.php
+│ │ ├── UpdatePostAction.php
+│ │ └── DeletePostAction.php
+│ │
+│ ├── Models/ # Eloquent models
+│ │ └── Post.php
+│ │
+│ ├── DTO/ # Data Transfer Objects
+│ │ ├── CreatePostDTO.php
+│ │ └── UpdatePostDTO.php
+│ │
+│ ├── Events/ # Domain events
+│ │ └── PostCreated.php
+│ │
+│ ├── Listeners/ # Event listeners
+│ │ └── SendPostNotification.php
+│ │
+│ ├── Jobs/ # Queued jobs
+│ │ └── ProcessPost.php
+│ │
+│ ├── Policies/ # Authorization policies
+│ │ └── PostPolicy.php
+│ │
+│ ├── Providers/ # Service providers
+│ │ ├── BlogServiceProvider.php
+│ │ └── RouteServiceProvider.php
+│ │
+│ └── UI/
+│ ├── API/
+│ │ ├── Controllers/
+│ │ │ └── PostController.php
+│ │ ├── Requests/
+│ │ │ ├── CreatePostRequest.php
+│ │ │ └── UpdatePostRequest.php
+│ │ ├── Resources/
+│ │ │ └── PostResource.php
+│ │ ├── QueryWizards/
+│ │ │ └── PostsQueryWizard.php
+│ │ └── routes/
+│ │ └── v1.php
+│ │
+│ ├── WEB/
+│ │ ├── Controllers/
+│ │ ├── Requests/
+│ │ └── routes/
+│ │
+│ └── CLI/
+│ └── Commands/
+│
+├── database/
+│ ├── migrations/
+│ │ └── 2024_01_01_create_posts_table.php
+│ ├── seeders/
+│ │ └── PostSeeder.php
+│ └── factories/
+│ └── PostFactory.php
+│
+├── resources/
+│ └── views/
+│
+├── lang/
+│
+├── config/
+│
+└── tests/
+ ├── Unit/
+ ├── Feature/
+ └── API/
+```
+
+## Core Concepts
+
+### Module
+
+A **Module** represents a self-contained business domain. It's identified by its Composer package name (e.g., `app/blog`).
+
+```php
+use Laraneat\Modules\ModulesRepository;
+
+$repository = app(ModulesRepository::class);
+
+// Find a module
+$module = $repository->find('app/blog');
+
+// Get module properties
+$module->getName(); // "blog"
+$module->getStudlyName(); // "Blog"
+$module->getNamespace(); // "Modules\Blog"
+$module->getPath(); // "/path/to/modules/blog"
+$module->getProviders(); // ["Modules\Blog\Providers\BlogServiceProvider"]
+```
+
+### ModulesRepository
+
+The **ModulesRepository** discovers and manages all modules in your application.
+
+```php
+use Laraneat\Modules\ModulesRepository;
+
+$repository = app(ModulesRepository::class);
+
+// Get all modules
+$modules = $repository->getModules();
+
+// Check if module exists
+$repository->has('app/blog');
+
+// Find module by name
+$repository->filterByName('Blog');
+
+// Delete a module
+$repository->delete('app/blog');
+```
+
+### Actions
+
+**Actions** are the core of the architecture. Using `lorisleiva/laravel-actions`, they serve dual purposes:
+- **Business Logic** via `handle()` method - can be called from anywhere (other actions, jobs, commands)
+- **HTTP Controller** via `asController()` method - handles HTTP requests directly
+
+```php
+// src/Actions/CreatePostAction.php
+namespace Modules\Blog\Actions;
+
+use Lorisleiva\Actions\Concerns\AsAction;
+use Modules\Blog\DTO\CreatePostDTO;
+use Modules\Blog\Models\Post;
+use Modules\Blog\UI\API\Requests\CreatePostRequest;
+use Modules\Blog\UI\API\Resources\PostResource;
+use Illuminate\Http\JsonResponse;
+
+class CreatePostAction
+{
+ use AsAction;
+
+ // Core business logic - reusable from anywhere
+ public function handle(CreatePostDTO $dto): Post
+ {
+ return Post::create($dto->all());
+ }
+
+ // HTTP entry point - acts as controller
+ public function asController(CreatePostRequest $request): JsonResponse
+ {
+ $post = $this->handle($request->toDTO());
+
+ return (new PostResource($post))->created();
+ }
+}
+```
+
+**Routes point directly to Actions:**
+
+```php
+// routes/v1.php
+Route::post('/posts', CreatePostAction::class);
+Route::get('/posts', ListPostsAction::class);
+Route::get('/posts/{post}', ViewPostAction::class);
+Route::put('/posts/{post}', UpdatePostAction::class);
+Route::delete('/posts/{post}', DeletePostAction::class);
+```
+
+### DTOs (Data Transfer Objects)
+
+**DTOs** are simple objects that carry data between layers.
+
+```php
+// src/DTO/CreatePostDTO.php
+namespace Modules\Blog\DTO;
+
+class CreatePostDTO
+{
+ public function __construct(
+ public readonly string $title,
+ public readonly string $content,
+ public readonly int $authorId,
+ ) {}
+
+ public static function fromRequest(CreatePostRequest $request): self
+ {
+ return new self(
+ title: $request->validated('title'),
+ content: $request->validated('content'),
+ authorId: $request->user()->id,
+ );
+ }
+}
+```
+
+### Module Service Provider
+
+Each module has a service provider that extends `ModuleServiceProvider`:
+
+```php
+// src/Providers/BlogServiceProvider.php
+namespace Modules\Blog\Providers;
+
+use Laraneat\Modules\Support\ModuleServiceProvider;
+
+class BlogServiceProvider extends ModuleServiceProvider
+{
+ public function boot(): void
+ {
+ // Load module commands
+ $this->loadCommandsFrom([
+ 'Modules\\Blog\\UI\\CLI\\Commands' => __DIR__ . '/../UI/CLI/Commands',
+ ]);
+
+ // Load migrations
+ $this->loadMigrationsFrom(__DIR__ . '/../../database/migrations');
+
+ // Load views
+ $this->loadViewsFrom(__DIR__ . '/../../resources/views', 'blog');
+ }
+}
+```
+
+## Configuration
+
+After publishing, edit `config/modules.php`:
+
+```php
+return [
+ // Where modules are stored
+ 'path' => base_path('modules'),
+
+ // Base namespace for all modules
+ 'namespace' => 'Modules',
+
+ // Custom stubs location (optional)
+ 'custom_stubs' => base_path('stubs/modules'),
+
+ // Composer settings for generated modules
+ 'composer' => [
+ 'vendor' => 'app',
+ 'author' => [
+ 'name' => 'Your Name',
+ 'email' => 'your@email.com',
+ ],
+ ],
+
+ // Component path/namespace mappings
+ 'components' => [
+ 'action' => [
+ 'path' => 'src/Actions',
+ 'namespace' => 'Actions',
+ ],
+ 'model' => [
+ 'path' => 'src/Models',
+ 'namespace' => 'Models',
+ ],
+ // ... more components
+ ],
+
+ // Enable manifest caching (recommended for production)
+ 'cache' => [
+ 'enabled' => env('APP_ENV') === 'production',
+ ],
+];
+```
+
+## Artisan Commands
+
+### Module Management
+
+| Command | Description |
+|---------|-------------|
+| `module:list` | Display all registered modules |
+| `module:sync` | Refresh manifest and sync with Composer |
+| `module:delete {package}` | Delete a module completely |
+| `module:cache` | Build module manifest cache |
+| `module:cache:clear` | Clear module manifest cache |
+
+### Module Creation
+
+```bash
+# Create module with interactive preset selection
+php artisan module:make Blog
+
+# Create with specific preset
+php artisan module:make Blog --preset=api --entity=Post
+```
+
+### Component Generators
+
+| Command | Description |
+|---------|-------------|
+| `module:make:action` | Create an Action class |
+| `module:make:controller` | Create a Controller (--ui=api\|web) |
+| `module:make:model` | Create an Eloquent Model |
+| `module:make:migration` | Create a database migration |
+| `module:make:request` | Create a Form Request |
+| `module:make:resource` | Create an API Resource |
+| `module:make:dto` | Create a DTO class |
+| `module:make:event` | Create an Event class |
+| `module:make:listener` | Create an Event Listener |
+| `module:make:job` | Create a Job class |
+| `module:make:policy` | Create a Policy class |
+| `module:make:provider` | Create a Service Provider |
+| `module:make:middleware` | Create Middleware |
+| `module:make:command` | Create a Console Command |
+| `module:make:factory` | Create a Model Factory |
+| `module:make:seeder` | Create a Database Seeder |
+| `module:make:test` | Create a Test class |
+| `module:make:observer` | Create a Model Observer |
+| `module:make:notification` | Create a Notification |
+| `module:make:mail` | Create a Mailable |
+| `module:make:rule` | Create a Validation Rule |
+| `module:make:query-wizard` | Create a QueryWizard |
+| `module:make:route` | Create a Route file |
+| `module:make:exception` | Create an Exception class |
+
+### Migration Commands
+
+| Command | Description |
+|---------|-------------|
+| `module:migrate` | Run module migrations |
+| `module:migrate:rollback` | Rollback module migrations |
+| `module:migrate:reset` | Reset all module migrations |
+| `module:migrate:refresh` | Refresh module migrations |
+| `module:migrate:status` | Show migration status |
+
+## Component Types
+
+The package supports 30+ component types organized by architectural layers:
+
+### UI Layer
+
+**API Components:**
+- `ApiController` - REST API controllers
+- `ApiRequest` - API form requests
+- `ApiResource` - API JSON resources
+- `ApiRoute` - API route files
+- `ApiQueryWizard` - Query builder wrappers
+- `ApiTest` - API integration tests
+
+**WEB Components:**
+- `WebController` - Web controllers
+- `WebRequest` - Web form requests
+- `WebRoute` - Web route files
+- `WebTest` - Web integration tests
+
+**CLI Components:**
+- `CliCommand` - Artisan commands
+- `CliTest` - Command tests
+
+### Domain Layer
+
+- `Action` - Business logic actions
+- `Model` - Eloquent models
+- `Dto` - Data Transfer Objects
+- `Event` - Domain events
+- `Listener` - Event listeners
+- `Job` - Queued jobs
+- `Rule` - Validation rules
+- `Observer` - Model observers
+
+### Infrastructure Layer
+
+- `Provider` - Service providers
+- `Middleware` - HTTP middleware
+- `Policy` - Authorization policies
+- `Mail` - Mailable classes
+- `Notification` - Notifications
+
+### Database Layer
+
+- `Migration` - Database migrations
+- `Seeder` - Database seeders
+- `Factory` - Model factories
+
+## Module Presets
+
+### Plain Preset (Default)
+
+Basic module with minimal structure:
+- Service providers only
+- Empty directory structure
+
+```bash
+php artisan module:make Blog --preset=plain
+```
+
+### Base Preset
+
+Includes database layer components:
+- Model with migrations
+- Factory for testing
+- Seeder with permissions
+- Authorization policy
+
+```bash
+php artisan module:make Blog --preset=base --entity=Post
+```
+
+### API Preset
+
+Complete REST API module:
+- All base preset components
+- CRUD controllers
+- Form requests (create, update, delete, list, view)
+- API resources
+- QueryWizard for filtering/sorting
+- DTOs for data transfer
+- Complete route file
+- Full test coverage
+
+```bash
+php artisan module:make Blog --preset=api --entity=Post
+```
+
+## Best Practices
+
+### 1. Keep Modules Independent
+
+Modules should be loosely coupled. If module A depends on module B, consider:
+- Using events for communication
+- Creating shared interfaces
+- Moving shared code to a separate package
+
+### 2. Separate HTTP Logic from Business Logic
+
+Keep `asController()` thin - it should only handle HTTP concerns. Put business logic in `handle()`:
+
+```php
+class CreatePostAction
+{
+ use AsAction;
+
+ // Business logic - reusable, testable
+ public function handle(CreatePostDTO $dto): Post
+ {
+ $post = Post::create($dto->all());
+ event(new PostCreated($post));
+
+ return $post;
+ }
+
+ // HTTP concerns only - request/response handling
+ public function asController(CreatePostRequest $request): JsonResponse
+ {
+ $post = $this->handle($request->toDTO());
+
+ return (new PostResource($post))->created();
+ }
+}
+```
+
+### 3. Reuse Actions Across Contexts
+
+Actions can be called from multiple places:
+
+```php
+// From another Action
+class ImportPostsAction
+{
+ public function __construct(private CreatePostAction $createPost) {}
+
+ public function handle(array $posts): void
+ {
+ foreach ($posts as $postData) {
+ $this->createPost->handle(new CreatePostDTO(...$postData));
+ }
+ }
+}
+
+// From a Job
+class ProcessImportJob implements ShouldQueue
+{
+ public function handle(CreatePostAction $action): void
+ {
+ $action->handle($this->dto);
+ }
+}
+
+// From a Command
+class SeedPostsCommand extends Command
+{
+ public function handle(CreatePostAction $action): void
+ {
+ $action->handle(new CreatePostDTO(...));
+ }
+}
+```
+
+### 4. Use DTOs for Data Transfer
+
+DTOs provide type safety and clear contracts:
+
+```php
+class CreatePostDTO
+{
+ public function __construct(
+ public readonly string $title,
+ public readonly string $content,
+ public readonly int $authorId,
+ ) {}
+
+ public function all(): array
+ {
+ return [
+ 'title' => $this->title,
+ 'content' => $this->content,
+ 'author_id' => $this->authorId,
+ ];
+ }
+}
+```
+
+### 5. Organize Routes by Version
+
+For APIs, version your routes:
+
+```
+routes/
+├── v1.php # Version 1 routes
+└── v2.php # Version 2 routes
+```
+
+### 6. Write Tests
+
+Each module should have comprehensive tests:
+
+```bash
+# Run all module tests
+./vendor/bin/pest modules/blog/tests
+
+# Run specific test
+./vendor/bin/pest --filter "can create post"
+```
+
+### 7. Use Caching in Production
+
+Enable manifest caching for better performance:
+
+```php
+// config/modules.php
+'cache' => [
+ 'enabled' => env('APP_ENV') === 'production',
+],
+```
+
+Run after deployment:
+```bash
+php artisan module:cache
+```
+
+## License
+
+MIT License. See [LICENSE](LICENSE) for details.
diff --git a/composer.json b/composer.json
index 76bcb02..2337c17 100644
--- a/composer.json
+++ b/composer.json
@@ -1,10 +1,10 @@
{
"name": "laraneat/modules",
"description": "Laraneat modules.",
- "homepage": "https://github.com/laraneat/core/",
+ "homepage": "https://github.com/laraneat/modules/",
"support": {
- "issues": "https://github.com/laraneat/core/issues",
- "source": "https://github.com/laraneat/core"
+ "issues": "https://github.com/laraneat/modules/issues",
+ "source": "https://github.com/laraneat/modules"
},
"authors": [
{
@@ -24,41 +24,46 @@
],
"license": "MIT",
"require": {
- "php": "^8.0",
+ "php": "^8.1",
"ext-json": "*",
- "laravel/framework": "^10.0"
+ "composer/composer": "^2.1",
+ "laravel/framework": "^10.0 || ^11.0 || ^12.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.48",
- "mockery/mockery": "~1.0",
- "orchestra/testbench": "^8.2",
- "phpstan/phpstan": "^1.10",
- "phpunit/phpunit": "^10.5",
+ "larastan/larastan": "^2.0 || ^3.0",
+ "mockery/mockery": "^1.0",
+ "orchestra/testbench": "^8.0 || ^9.0 || ^10.0",
+ "pestphp/pest": "^2.31 || ^3.0",
+ "pestphp/pest-plugin-laravel": "^2.0 || ^3.0",
+ "phpstan/phpstan": "^1.10.58 || ^2.0",
"roave/security-advisories": "dev-latest",
- "spatie/phpunit-snapshot-assertions": "^5.1"
+ "spatie/pest-plugin-snapshots": "^2.1"
},
"autoload": {
"psr-4": {
"Laraneat\\Modules\\": "src"
- },
- "files": [
- "src/helpers.php"
- ]
+ }
},
"autoload-dev": {
"psr-4": {
"Laraneat\\Modules\\Tests\\": "tests",
- "App\\": "tests/laravel/app",
- "App\\Modules\\Article\\": "tests/fixtures/stubs/valid/Article"
+ "App\\": "tests/fixtures/laravel/app",
+ "Modules\\": "tests/fixtures/laravel/modules"
}
},
"suggest": {
- "wikimedia/composer-merge-plugin": "Allows the ability to create and merge composer.json files for your individual modules for module-specific dependency management."
+ "lorisleiva/laravel-actions": "Laravel components that take care of one specific task",
+ "jackardios/laravel-query-wizard": "Easily build Eloquent queries from API requests",
+ "spatie/laravel-data": "Powerful data objects for Laravel"
},
"extra": {
"laravel": {
"providers": [
- "Laraneat\\Modules\\ModulesServiceProvider"
+ "Laraneat\\Modules\\Providers\\ComposerServiceProvider",
+ "Laraneat\\Modules\\Providers\\ConsoleServiceProvider",
+ "Laraneat\\Modules\\Providers\\ModulesRepositoryServiceProvider",
+ "Laraneat\\Modules\\Providers\\ModulesServiceProvider"
],
"aliases": {
"Modules": "Laraneat\\Modules\\Facades\\Modules"
@@ -66,17 +71,16 @@
}
},
"scripts": {
- "update-snapshots": "./vendor/bin/phpunit --no-coverage -d --update-snapshots",
- "test": "vendor/bin/phpunit",
- "test-coverage": "vendor/bin/phpunit --debug --coverage-html coverage",
- "pcf": "vendor/bin/php-cs-fixer fix --verbose",
+ "analyse" : "./vendor/bin/phpstan analyse --memory-limit=256M",
+ "test" : "./vendor/bin/pest --no-coverage",
+ "test-coverage" : "./vendor/bin/pest --coverage-html coverage",
+ "update-snapshots": "./vendor/bin/pest --no-coverage --update-snapshots",
+ "format": "./vendor/bin/php-cs-fixer fix --allow-risky=yes",
"post-autoload-dump": [
"@php ./vendor/bin/testbench package:discover --ansi"
]
},
- "config": {
- "optimize-autoloader": true,
- "preferred-install": "dist",
+ "config" : {
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true
diff --git a/config/config.php b/config/config.php
index 653752f..7848b1c 100755
--- a/config/config.php
+++ b/config/config.php
@@ -1,301 +1,229 @@
[
- /*
- |--------------------------------------------------------------------------
- | The path to assets
- |--------------------------------------------------------------------------
- |
- | This path is used to store public assets of modules
- |
- */
- 'assets' => public_path('modules'),
- ],
-
- 'generator' => [
- /*
- |--------------------------------------------------------------------------
- | Modules path
- |--------------------------------------------------------------------------
- |
- | This path used for save the generated module. This path also will be added
- | automatically to list of scanned folders.
- |
- */
- 'path' => base_path('app/Modules'),
-
- /*
- |--------------------------------------------------------------------------
- | Default Module Namespace
- |--------------------------------------------------------------------------
- |
- | Default module namespace.
- |
- */
- 'namespace' => 'App\\Modules',
-
- /*
- |--------------------------------------------------------------------------
- | Custom generator stubs path
- |--------------------------------------------------------------------------
- |
- | Place your custom stubs in this folder
- |
- */
- 'custom_stubs' => base_path('app/Ship/Generators/custom-stubs'),
-
- /*
- |--------------------------------------------------------------------------
- | User model class
- |--------------------------------------------------------------------------
- |
- | Customize the User model of the application
- |
- */
- 'user_model' => null,
-
- /*
- |--------------------------------------------------------------------------
- | "Create permission" classes
- |--------------------------------------------------------------------------
- |
- | Customize "create permission" classes
- |
- */
- 'create_permission' => [
- 'action' => null,
- 'dto' => null
- ],
+ /*
+ |--------------------------------------------------------------------------
+ | Modules path
+ |--------------------------------------------------------------------------
+ |
+ | This path used for scan and save the generated module.
+ |
+ */
+ 'path' => base_path('modules'),
- /*
- |--------------------------------------------------------------------------
- | Component paths
- |--------------------------------------------------------------------------
- |
- | Customize the paths where the folders will be generated.
- | Set the generate key to `false` to not generate that folder when creating
- | a module
- |
- */
- 'components' => [
- 'action' => [
- 'path' => 'Actions',
- 'generate' => true
- ],
- 'api-controller' => [
- 'path' => 'UI/API/Controllers',
- 'generate' => false
- ],
- 'api-query-wizard' => [
- 'path' => 'UI/API/QueryWizards',
- 'generate' => true
- ],
- 'api-request' => [
- 'path' => 'UI/API/Requests',
- 'generate' => true
- ],
- 'api-resource' => [
- 'path' => 'UI/API/Resources',
- 'generate' => true
- ],
- 'api-route' => [
- 'path' => 'UI/API/Routes',
- 'generate' => true
- ],
- 'api-test' => [
- 'path' => 'UI/API/Tests',
- 'generate' => true
- ],
- 'cli-command' => [
- 'path' => 'UI/CLI/Commands',
- 'generate' => false
- ],
- 'cli-test' => [
- 'path' => 'UI/CLI/Tests',
- 'generate' => false
- ],
- 'dto' => [
- 'path' => 'DTO',
- 'generate' => true
- ],
- 'event' => [
- 'path' => 'Events',
- 'generate' => false
- ],
- 'exception' => [
- 'path' => 'Exceptions',
- 'generate' => false
- ],
- 'factory' => [
- 'path' => 'Data/Factories',
- 'generate' => true
- ],
- 'feature-test' => [
- 'path' => 'Tests/Feature',
- 'generate' => false
- ],
- 'job' => [
- 'path' => 'Jobs',
- 'generate' => false
- ],
- 'lang' => [
- 'path' => 'Resources/lang',
- 'generate' => false
- ],
- 'listener' => [
- 'path' => 'Listeners',
- 'generate' => false
- ],
- 'mail' => [
- 'path' => 'Mails',
- 'generate' => false
- ],
- 'middleware' => [
- 'path' => 'Middleware',
- 'generate' => false
- ],
- 'migration' => [
- 'path' => 'Data/Migrations',
- 'generate' => true
- ],
- 'model' => [
- 'path' => 'Models',
- 'generate' => true
- ],
- 'notification' => [
- 'path' => 'Notifications',
- 'generate' => false
- ],
- 'observer' => [
- 'path' => 'Observers',
- 'generate' => false
- ],
- 'policy' => [
- 'path' => 'Policies',
- 'generate' => true
- ],
- 'provider' => [
- 'path' => 'Providers',
- 'generate' => true
- ],
- 'rule' => [
- 'path' => 'Rules',
- 'generate' => false
- ],
- 'seeder' => [
- 'path' => 'Data/Seeders',
- 'generate' => true
- ],
- 'web-controller' => [
- 'path' => 'UI/WEB/Controllers',
- 'generate' => false
- ],
- 'web-request' => [
- 'path' => 'UI/WEB/Requests',
- 'generate' => false,
- ],
- 'web-route' => [
- 'path' => 'UI/WEB/Routes',
- 'generate' => false
- ],
- 'web-test' => [
- 'path' => 'UI/WEB/Tests',
- 'generate' => false
- ],
- 'view' => [
- 'path' => 'Resources/views',
- 'generate' => false
- ],
- 'unit-test' => [
- 'path' => 'Tests/Unit',
- 'generate' => false
- ],
- ],
- ],
+ /*
+ |--------------------------------------------------------------------------
+ | Module namespace prefix
+ |--------------------------------------------------------------------------
+ |
+ | Prefix for the namespace of the generated modules
+ |
+ */
+ 'namespace' => 'Modules',
/*
|--------------------------------------------------------------------------
- | Scan Path
+ | Custom generator stubs 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.
+ | Place your custom stubs in this folder
|
*/
- 'scan' => [
- 'enabled' => false,
- 'paths' => [
- base_path('vendor/*/*'),
- ],
- ],
+ 'custom_stubs' => base_path('stubs/modules'),
/*
|--------------------------------------------------------------------------
| Composer File Template
|--------------------------------------------------------------------------
|
- | Here is the config for composer.json file, generated by this package
+ | Configuration composer.json of generated modules
|
*/
'composer' => [
- 'vendor' => 'example',
+ 'vendor' => 'app',
'author' => [
- 'name' => 'Example name',
- 'email' => 'example@example.com',
+ 'name' => 'Example',
+ 'email' => 'example@example.com'
],
- 'composer-output' => false,
],
/*
|--------------------------------------------------------------------------
- | Caching
+ | User model class
|--------------------------------------------------------------------------
|
- | Here is the config for setting up caching feature for scanned modules.
+ | Customize the User model of the application
|
*/
- 'cache' => [
- 'enabled' => env('APP_ENV', 'production') === 'production',
- 'key' => 'laraneat.modules',
- 'lifetime' => null, // store cache indefinitely
- ],
+ 'user_model' => null,
/*
|--------------------------------------------------------------------------
- | Choose what laraneat/modules will register as custom namespaces.
- | Setting one to false will require you to register that part
- | in your own Service Provider class.
+ | "Create permission" classes
|--------------------------------------------------------------------------
+ |
+ | Customize "create permission" classes
+ |
*/
- 'register' => [
- /**
- * load files on boot or register method
- *
- * @example boot|register
- */
- 'files' => 'register',
+ 'create_permission' => [
+ 'action' => null,
+ 'dto' => null
],
/*
|--------------------------------------------------------------------------
- | Activators
+ | Component paths
|--------------------------------------------------------------------------
|
- | 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
+ | Customize the paths where the folders will be generated.
+ |
*/
- 'activators' => [
- 'file' => [
- 'class' => FileActivator::class,
- 'statuses-file' => base_path('modules_statuses.json'),
- 'cache-key' => 'laraneat.activator.installed',
- 'cache-lifetime' => null, // store cache indefinitely
+ 'components' => [
+ ModuleComponentType::Action->value => [
+ 'path' => 'src/Actions',
+ 'namespace' => 'Actions'
+ ],
+ ModuleComponentType::ApiController->value => [
+ 'path' => 'src/UI/API/Controllers',
+ 'namespace' => 'UI\\API\\Controllers'
+ ],
+ ModuleComponentType::ApiQueryWizard->value => [
+ 'path' => 'src/UI/API/QueryWizards',
+ 'namespace' => 'UI\\API\\QueryWizards'
+ ],
+ ModuleComponentType::ApiRequest->value => [
+ 'path' => 'src/UI/API/Requests',
+ 'namespace' => 'UI\\API\\Requests'
+ ],
+ ModuleComponentType::ApiResource->value => [
+ 'path' => 'src/UI/API/Resources',
+ 'namespace' => 'UI\\API\\Resources'
+ ],
+ ModuleComponentType::ApiRoute->value => [
+ 'path' => 'src/UI/API/routes',
+ 'namespace' => 'UI\\API\\Routes'
+ ],
+ ModuleComponentType::ApiTest->value => [
+ 'path' => 'tests/UI/API',
+ 'namespace' => 'Tests\\UI\\API'
+ ],
+ ModuleComponentType::CliCommand->value => [
+ 'path' => 'src/UI/CLI/Commands',
+ 'namespace' => 'UI\\CLI\\Commands'
+ ],
+ ModuleComponentType::CliTest->value => [
+ 'path' => 'tests/UI/CLI',
+ 'namespace' => 'Tests\\UI\\CLI'
+ ],
+ ModuleComponentType::Config->value => [
+ 'path' => 'config'
+ ],
+ ModuleComponentType::Dto->value => [
+ 'path' => 'src/DTO',
+ 'namespace' => 'DTO'
+ ],
+ ModuleComponentType::Event->value => [
+ 'path' => 'src/Events',
+ 'namespace' => 'Events'
+ ],
+ ModuleComponentType::Exception->value => [
+ 'path' => 'src/Exceptions',
+ 'namespace' => 'Exceptions'
+ ],
+ ModuleComponentType::Factory->value => [
+ 'path' => 'database/factories',
+ 'namespace' => 'Database\\Factories'
+ ],
+ ModuleComponentType::FeatureTest->value => [
+ 'path' => 'tests/Feature',
+ 'namespace' => 'Tests\\Feature'
+ ],
+ ModuleComponentType::Job->value => [
+ 'path' => 'src/Jobs',
+ 'namespace' => 'Jobs'
+ ],
+ ModuleComponentType::Lang->value => [
+ 'path' => 'lang'
+ ],
+ ModuleComponentType::Listener->value => [
+ 'path' => 'src/Listeners',
+ 'namespace' => 'Listeners'
+ ],
+ ModuleComponentType::Mail->value => [
+ 'path' => 'src/Mails',
+ 'namespace' => 'Mails'
+ ],
+ ModuleComponentType::Middleware->value => [
+ 'path' => 'src/Middleware',
+ 'namespace' => 'Middleware'
+ ],
+ ModuleComponentType::Migration->value => [
+ 'path' => 'database/migrations'
+ ],
+ ModuleComponentType::Model->value => [
+ 'path' => 'src/Models',
+ 'namespace' => 'Models'
+ ],
+ ModuleComponentType::Notification->value => [
+ 'path' => 'src/Notifications',
+ 'namespace' => 'Notifications'
+ ],
+ ModuleComponentType::Observer->value => [
+ 'path' => 'src/Observers',
+ 'namespace' => 'Observers'
+ ],
+ ModuleComponentType::Policy->value => [
+ 'path' => 'src/Policies',
+ 'namespace' => 'Policies'
+ ],
+ ModuleComponentType::Provider->value => [
+ 'path' => 'src/Providers',
+ 'namespace' => 'Providers'
+ ],
+ ModuleComponentType::Rule->value => [
+ 'path' => 'src/Rules',
+ 'namespace' => 'Rules'
+ ],
+ ModuleComponentType::Seeder->value => [
+ 'path' => 'database/seeders',
+ 'namespace' => 'Database\\Seeders'
+ ],
+ ModuleComponentType::UnitTest->value => [
+ 'path' => 'tests/Unit',
+ 'namespace' => 'Tests\\Unit'
+ ],
+ ModuleComponentType::View->value => [
+ 'path' => 'resources/views'
+ ],
+ ModuleComponentType::WebController->value => [
+ 'path' => 'src/UI/WEB/Controllers',
+ 'namespace' => 'UI\\WEB\\Controllers'
+ ],
+ ModuleComponentType::WebRequest->value => [
+ 'path' => 'src/UI/WEB/Requests',
+ 'namespace' => 'UI\\WEB\\Requests'
+ ],
+ ModuleComponentType::WebRoute->value => [
+ 'path' => 'src/UI/WEB/routes',
+ 'namespace' => 'UI\\WEB\\Routes'
+ ],
+ ModuleComponentType::WebTest->value => [
+ 'path' => 'tests/UI/WEB',
+ 'namespace' => 'Tests\\UI\\WEB'
],
],
- 'activator' => 'file',
+ /*
+ |--------------------------------------------------------------------------
+ | Caching
+ |--------------------------------------------------------------------------
+ |
+ | Here is the config for setting up caching feature for scanned modules.
+ |
+ */
+ 'cache' => [
+ 'enabled' => env('APP_ENV', 'production') === 'production',
+ ],
];
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 0000000..4a797fd
--- /dev/null
+++ b/phpstan-baseline.neon
@@ -0,0 +1,3 @@
+parameters:
+ ignoreErrors:
+ - "#Unsafe usage of new static#"
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 0000000..db492d2
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,22 @@
+includes:
+ - phpstan-baseline.neon
+ - vendor/larastan/larastan/extension.neon
+
+parameters:
+ level: 5
+ paths:
+ - src
+ tmpDir: build/phpstan
+ reportUnmatchedIgnoredErrors: true
+ checkOctaneCompatibility: true
+ checkModelProperties: true
+ ignoreErrors:
+ # These traits are used in stubs for generated code
+ - identifier: trait.unused
+ path: src/Support/Concerns/CanLoadRoutesFromDirectory.php
+ - identifier: trait.unused
+ path: src/Support/Concerns/CanRunModuleSeeders.php
+ - identifier: trait.unused
+ path: src/Support/Concerns/InteractsWithTestUser.php
+ - identifier: trait.unused
+ path: src/Support/Concerns/WithJsonResponseHelpers.php
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..417198b
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ ./tests
+
+
+
+
+ ./src
+
+
+
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
deleted file mode 100644
index 9912507..0000000
--- a/phpunit.xml.dist
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- tests
-
-
-
-
-
-
-
- src/
-
-
-
diff --git a/src/Activators/FileActivator.php b/src/Activators/FileActivator.php
deleted file mode 100755
index 0837e8b..0000000
--- a/src/Activators/FileActivator.php
+++ /dev/null
@@ -1,196 +0,0 @@
-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
- */
- public function getStatusesFilePath(): string
- {
- return $this->statusesFile;
- }
-
- /**
- * @inheritDoc
- * @see ActivatorInterface::reset()
- */
- public function reset(): void
- {
- if ($this->files->exists($this->statusesFile)) {
- $this->files->delete($this->statusesFile);
- }
- $this->modulesStatuses = [];
- $this->flushCache();
- }
-
- /**
- * @inheritDoc
- * @see ActivatorInterface::enable()
- */
- public function enable(Module $module): void
- {
- $this->setActiveByName($module->getName(), true);
- }
-
- /**
- * @inheritDoc
- * @see ActivatorInterface::disable()
- */
- public function disable(Module $module): void
- {
- $this->setActiveByName($module->getName(), false);
- }
-
- /**
- * @inheritDoc
- * @see ActivatorInterface::hasStatus()
- */
- public function hasStatus(Module $module, bool $status): bool
- {
- if (!isset($this->modulesStatuses[$module->getName()])) {
- return $status === false;
- }
-
- return $this->modulesStatuses[$module->getName()] === $status;
- }
-
- /**
- * @inheritDoc
- * @see ActivatorInterface::setActive()
- */
- public function setActive(Module $module, bool $active): void
- {
- $this->setActiveByName($module->getName(), $active);
- }
-
- /**
- * @inheritDoc
- * @see ActivatorInterface::setActiveByName()
- */
- public function setActiveByName(string $moduleName, bool $active): void
- {
- $this->modulesStatuses[$moduleName] = $active;
- $this->writeJson();
- $this->flushCache();
- }
-
- /**
- * @inheritDoc
- * @see ActivatorInterface::delete()
- */
- 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
- */
- protected function writeJson(): void
- {
- $this->files->put($this->statusesFile, json_encode($this->modulesStatuses, JSON_PRETTY_PRINT));
- }
-
- /**
- * Reads the json file that contains the activation statuses.
- */
- protected 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.
- */
- protected function getModulesStatuses(): array
- {
- if (!$this->config->get('modules.cache.enabled')) {
- return $this->readJson();
- }
-
- return $this->cache->remember($this->cacheKey, $this->cacheLifetime, function () {
- return $this->readJson();
- });
- }
-
- /**
- * Reads a config parameter under the 'activators.file' key
- */
- protected function config(string $key, $default = null)
- {
- return $this->config->get('modules.activators.file.' . $key, $default);
- }
-
- /**
- * Flush the modules activation statuses cache
- */
- public function flushCache(): void
- {
- $this->cache->forget($this->cacheKey);
- }
-}
diff --git a/src/Commands/BaseCommand.php b/src/Commands/BaseCommand.php
new file mode 100644
index 0000000..5bb23b9
--- /dev/null
+++ b/src/Commands/BaseCommand.php
@@ -0,0 +1,187 @@
+|Module
+ *
+ * @throws ModuleNotFound
+ * @throws ModuleHasNonUniquePackageName
+ * @throws ModuleHasNoNamespace
+ */
+ protected function getModuleArgumentOrFail(): array|Module
+ {
+ $allPackageNames = array_keys($this->modulesRepository->getModules());
+ $moduleArgument = $this->input->getArgument('module');
+ $multipleModuleMode = is_array($moduleArgument);
+
+ if ($multipleModuleMode) {
+ $moduleArgument = array_values(array_unique($moduleArgument));
+
+ if (empty($moduleArgument)) {
+ $moduleArgument = multiselect(
+ label: 'Select one or more module',
+ options: [
+ 'all' => 'All modules',
+ ...array_combine($allPackageNames, $allPackageNames),
+ ],
+ required: 'You must select at least one module',
+ );
+ }
+
+ if (in_array('all', $moduleArgument, true)) {
+ $moduleArgument = $allPackageNames;
+ }
+ } else {
+ if (empty($moduleArgument)) {
+ $moduleArgument = select(
+ label: 'Select one module',
+ options: $allPackageNames,
+ required: 'You must select a module',
+ );
+ }
+ }
+
+ $this->input->setArgument('module', value: $moduleArgument);
+
+ if (! $multipleModuleMode) {
+ return $this->findModuleByNameOrPackageNameOrFail($moduleArgument);
+ }
+
+ return collect($moduleArgument)
+ ->map(fn (string $moduleNameOrPackageName)
+ => $this->findModuleByNameOrPackageNameOrFail($moduleNameOrPackageName))
+ ->unique(fn (Module $module) => $module->getPackageName())
+ ->values()
+ ->all();
+ }
+
+ /**
+ * @throws ModuleNotFound
+ * @throws ModuleHasNonUniquePackageName
+ * @throws ModuleHasNoNamespace
+ */
+ protected function findModuleByNameOrPackageNameOrFail($moduleNameOrPackageName): Module
+ {
+ if ($foundModule = $this->modulesRepository->find($moduleNameOrPackageName)) {
+ return $foundModule;
+ }
+
+ $foundModules = collect($this->modulesRepository->filterByName($moduleNameOrPackageName));
+ $numberOfFoundModules = $foundModules->count();
+
+ if ($numberOfFoundModules === 0) {
+ throw ModuleNotFound::makeForNameOrPackageName($moduleNameOrPackageName);
+ }
+
+ if ($numberOfFoundModules === 1) {
+ return $foundModules->first();
+ }
+
+ $selectedPackageName = $this->choice(
+ "$numberOfFoundModules modules with name '{$moduleNameOrPackageName}' found, please select one module from those found",
+ $foundModules->keys()->all(),
+ );
+
+
+ return $this->modulesRepository->findOrFail($selectedPackageName);
+ }
+
+ /**
+ * Checks if the option is set (via CLI), otherwise asks the user for a value
+ *
+ * @throws InvalidOptionException
+ */
+ protected function getOptionOrAsk(
+ string $optionName,
+ string $question,
+ ?string $default = null,
+ bool $required = true
+ ): ?string {
+ $value = $this->option($optionName);
+
+ if ($value === '' || $value === null) {
+ $value = trim($this->ask($question, $default));
+ }
+
+ if ($required && $value === '') {
+ throw new InvalidOptionException(
+ sprintf("The '%s' option is required", $optionName)
+ );
+ }
+
+ return $value;
+ }
+
+ /**
+ * Checks if the option is set (via CLI), otherwise proposes choices to the user
+ *
+ * @throws InvalidOptionException
+ */
+ protected function getOptionOrChoice(
+ string $optionName,
+ string $question,
+ array $choices,
+ ?string $default = null
+ ): ?string {
+ $value = $this->option($optionName);
+
+ if ($value === '' || $value === null) {
+ $value = $this->choice($question, $choices, $default);
+ } elseif (! in_array($value, $choices, true)) {
+ throw new InvalidOptionException(
+ sprintf(
+ "Wrong '%s' option value provided. Value should be one of '%s'.",
+ $optionName,
+ implode("' or '", $choices)
+ )
+ );
+ }
+
+ return $value;
+ }
+
+ /**
+ * Checks if the option is set (via CLI)
+ *
+ * @throws InvalidOptionException
+ */
+ protected function getOptionOneOf(
+ string $optionName,
+ array $choices,
+ ?string $default = null
+ ): ?string {
+ $value = $this->option($optionName) ?: $default;
+
+ if (! in_array($value, $choices, true)) {
+ throw new InvalidOptionException(
+ sprintf(
+ "Wrong '%s' option value provided. Value should be one of '%s'.",
+ $optionName,
+ implode("' or '", $choices)
+ )
+ );
+ }
+
+ return $value;
+ }
+}
diff --git a/src/Commands/BaseMigrationCommand.php b/src/Commands/BaseMigrationCommand.php
new file mode 100644
index 0000000..6d5fba3
--- /dev/null
+++ b/src/Commands/BaseMigrationCommand.php
@@ -0,0 +1,71 @@
+requiresConfirmation && ! $this->confirmToProceed()) {
+ return self::FAILURE;
+ }
+
+ try {
+ $modulesToHandle = $this->getModuleArgumentOrFail();
+ } catch (ModuleNotFound|ModuleHasNonUniquePackageName|ModuleHasNoNamespace $exception) {
+ $this->error($exception->getMessage());
+
+ return self::FAILURE;
+ }
+
+ foreach ($modulesToHandle as $module) {
+ $this->line('Running for module: ' . $module->getPackageName() . '');
+ $this->executeForModule($module);
+ }
+
+ return self::SUCCESS;
+ }
+
+ /**
+ * Execute the migration operation for a single module.
+ */
+ abstract protected function executeForModule(Module $module): void;
+
+ /**
+ * Get migration paths for a module.
+ *
+ * @return array
+ */
+ protected function getMigrationPaths(Module $module): array
+ {
+ /** @var Migrator|null $migrator */
+ $migrator = $this->laravel['migrator'] ?? null;
+
+ if ($migrator === null) {
+ return [];
+ }
+
+ return collect($migrator->paths())
+ ->filter(fn (string $path) => Str::startsWith($path, $module->getPath()))
+ ->values()
+ ->toArray();
+ }
+}
diff --git a/src/Commands/CacheClearCommand.php b/src/Commands/CacheClearCommand.php
index ff06446..641ecff 100644
--- a/src/Commands/CacheClearCommand.php
+++ b/src/Commands/CacheClearCommand.php
@@ -2,17 +2,14 @@
namespace Laraneat\Modules\Commands;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Facades\Modules;
-
-class CacheClearCommand extends Command
+class CacheClearCommand extends BaseCommand
{
/**
- * The console command name.
+ * The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:clear';
+ protected $signature = 'module:clear';
/**
* The console command description.
@@ -26,8 +23,8 @@ class CacheClearCommand extends Command
*/
public function handle(): int
{
- Modules::flushCache();
- $this->info("Modules cache cleared!");
+ $this->modulesRepository->pruneModulesManifest();
+ $this->components->info("Modules manifest cache cleared!");
return self::SUCCESS;
}
diff --git a/src/Commands/CacheCommand.php b/src/Commands/CacheCommand.php
index cd74be2..f065224 100644
--- a/src/Commands/CacheCommand.php
+++ b/src/Commands/CacheCommand.php
@@ -2,34 +2,29 @@
namespace Laraneat\Modules\Commands;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Facades\Modules;
-
-class CacheCommand extends Command
+class CacheCommand extends BaseCommand
{
/**
- * The console command name.
+ * The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:cache';
+ protected $signature = 'module:cache';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Create a modules cache.';
+ protected $description = 'Caches modules.';
/**
* Execute the console command.
*/
public function handle(): int
{
- $this->call('module:clear');
-
- Modules::getCached();
- $this->info("Modules cached successfully!");
+ $this->modulesRepository->buildModulesManifest();
+ $this->components->info("Modules manifest cached!");
return self::SUCCESS;
}
diff --git a/src/Commands/DisableCommand.php b/src/Commands/DisableCommand.php
deleted file mode 100755
index d1a96b3..0000000
--- a/src/Commands/DisableCommand.php
+++ /dev/null
@@ -1,81 +0,0 @@
-argument('module') === null) {
- $this->disableAll();
- }
-
- $module = Modules::findOrFail($this->argument('module'));
-
- if ($module->isEnabled()) {
- $module->disable();
-
- $this->info("Module [{$module}] disabled successful.");
- } else {
- $this->comment("Module [{$module}] has already disabled.");
- }
-
- return self::SUCCESS;
- }
-
- /**
- * disableAll
- *
- * @return void
- */
- public function disableAll(): void
- {
- $modules = Modules::all();
-
- foreach ($modules as $module) {
- if ($module->isEnabled()) {
- $module->disable();
-
- $this->info("Module [{$module}] disabled successful.");
- } else {
- $this->comment("Module [{$module}] has already disabled.");
- }
- }
- }
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'Module name.'],
- ];
- }
-}
diff --git a/src/Commands/DumpCommand.php b/src/Commands/DumpCommand.php
deleted file mode 100755
index 79880b3..0000000
--- a/src/Commands/DumpCommand.php
+++ /dev/null
@@ -1,65 +0,0 @@
-info('Generating optimized autoload modules.');
-
- if ($module = $this->argument('module')) {
- $this->dump($module);
- } else {
- foreach (Modules::all() as $module) {
- $this->dump($module->getStudlyName());
- }
- }
-
- return self::SUCCESS;
- }
-
- public function dump(string $moduleName): void
- {
- $module = Modules::findOrFail($moduleName);
-
- $this->line("Running for module: {$moduleName}");
-
- chdir($module->getPath());
-
- passthru('composer dump -o -n -q');
- }
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'Module name.'],
- ];
- }
-}
diff --git a/src/Commands/EnableCommand.php b/src/Commands/EnableCommand.php
deleted file mode 100755
index 049f763..0000000
--- a/src/Commands/EnableCommand.php
+++ /dev/null
@@ -1,83 +0,0 @@
-argument('module') === null) {
- $this->enableAll();
-
- return self::SUCCESS;
- }
-
- $module = Modules::findOrFail($this->argument('module'));
-
- if ($module->isDisabled()) {
- $module->enable();
-
- $this->info("Module [{$module}] enabled successful.");
- } else {
- $this->comment("Module [{$module}] has already enabled.");
- }
-
- return self::SUCCESS;
- }
-
- /**
- * enableAll
- *
- * @return void
- */
- public function enableAll()
- {
- $modules = Modules::all();
-
- foreach ($modules as $module) {
- if ($module->isDisabled()) {
- $module->enable();
-
- $this->info("Module [{$module}] enabled successful.");
- } else {
- $this->comment("Module [{$module}] has already enabled.");
- }
- }
- }
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'Module name.'],
- ];
- }
-}
diff --git a/src/Commands/Generators/ActionMakeCommand.php b/src/Commands/Generators/ActionMakeCommand.php
index b0b555e..94eb3b6 100644
--- a/src/Commands/Generators/ActionMakeCommand.php
+++ b/src/Commands/Generators/ActionMakeCommand.php
@@ -2,158 +2,143 @@
namespace Laraneat\Modules\Commands\Generators;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Str;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class ActionMakeCommand extends ComponentGeneratorCommand
+class ActionMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:action';
+ protected $signature = 'module:make:action
+ {name : The name of the action class}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--dto= : The class name of the DTO to be used in the action}
+ {--model= : The class name of the model to be used in the action}
+ {--request= : The class name of the request to be used in the action}
+ {--resource= : The class name of the resource to be used in the action}
+ {--wizard= : The class name of the query wizard to be used in the action}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new action for the specified module.';
-
- /**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'plain';
+ protected $description = 'Generate new action class for the specified module.';
/**
- * Module instance.
- *
- * @var Module
+ * The module component type.
*/
- protected Module $module;
+ protected ModuleComponentType $componentType = ModuleComponentType::Action;
/**
- * Component type.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $componentType;
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
- */
- protected string $nameArgument;
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
- ['dto', null, InputOption::VALUE_REQUIRED, 'The class name of the DTO to be used in the action.'],
- ['model', null, InputOption::VALUE_REQUIRED, 'The class name of the model to be used in the action.'],
- ['request', null, InputOption::VALUE_REQUIRED, 'The class name of the request to be used in the action.'],
- ['resource', null, InputOption::VALUE_REQUIRED, 'The class name of the resource to be used in the action.'],
- ['wizard', null, InputOption::VALUE_REQUIRED, 'The class name of the wizard to be used in the action.'],
+ 'name' => 'Enter the action class name',
];
}
- protected function prepare()
+ protected function beforeGenerate(): void
+ {
+ $this->ensurePackageIsInstalledOrWarn('lorisleiva/laravel-actions');
+ }
+
+ protected function getContents(): string
{
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
+ $stub = $this->getOptionOrChoice(
'stub',
'Select the stub you want to use for generator',
['plain', 'create', 'delete', 'list', 'update', 'view'],
'plain'
);
- $this->componentType = 'action';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
+ return Stub::create("action/$stub.stub", $this->getStubReplaces($stub))->render();
}
- protected function getTemplateContents(): string
+ /**
+ * @param string $stub
+ * @return array
+ */
+ protected function getStubReplaces(string $stub): array
{
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
- if ($this->stub !== 'plain') {
- if ($this->stub === 'create' || $this->stub === 'update') {
- $dto = $this->getOptionOrAsk(
- 'dto',
- 'Enter the class name of the DTO to be used in the request',
- '',
- true
- );
- $stubReplaces['dto'] = $this->getClass($dto);
- $stubReplaces['dtoEntity'] = Str::camel($stubReplaces['dto']);
- $stubReplaces['dtoNamespace'] = $this->getComponentNamespace($this->module, $dto, 'dto');
- }
-
- if ($this->stub !== 'delete') {
- $resource = $this->getOptionOrAsk(
- 'resource',
- 'Enter the class name of the resource to be used in the action',
- '',
- true
- );
- $stubReplaces['resource'] = $this->getClass($resource);
- $stubReplaces['resourceNamespace'] = $this->getComponentNamespace($this->module, $resource, 'api-resource');
-
- if (in_array($this->stub, ['list', 'view'], true)) {
- $wizard = $this->getOptionOrAsk(
- 'wizard',
- 'Enter the class name of the wizard to be used in the action',
- '',
- true
- );
- $stubReplaces['queryWizard'] = $this->getClass($wizard);
- $stubReplaces['queryWizardNamespace'] = $this->getComponentNamespace($this->module, $wizard, 'api-query-wizard');
- }
- }
+ if ($stub === 'plain') {
+ return $stubReplaces;
+ }
- $model = $this->getOptionOrAsk(
- 'model',
- 'Enter the class name of the model to be used in the action',
- '',
- true
+ if ($stub === 'create' || $stub === 'update') {
+ $dtoClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'dto',
+ question: 'Enter the class name of the DTO to be used in the action',
+ componentType: ModuleComponentType::Dto,
+ module: $this->module
);
- $stubReplaces['model'] = $this->getClass($model);
- $stubReplaces['modelEntity'] = Str::camel($stubReplaces['model']);
- $stubReplaces['modelNamespace'] = $this->getComponentNamespace($this->module, $model, 'model');
-
- $request = $this->getOptionOrAsk(
- 'request',
- 'Enter the class name of the request to be used in the action',
- '',
- true
+ $stubReplaces['dto'] = class_basename($dtoClass);
+ $stubReplaces['dtoCamelCase'] = Str::camel($stubReplaces['dto']);
+ $stubReplaces['dtoNamespace'] = $this->getNamespaceOfClass($dtoClass);
+ }
+
+ if ($stub !== 'delete') {
+ $resourceClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'resource',
+ question: 'Enter the class name of the resource to be used in the action',
+ componentType: ModuleComponentType::ApiResource,
+ module: $this->module
);
- $stubReplaces['request'] = $this->getClass($request);
- $stubReplaces['requestNamespace'] = $this->getComponentNamespace($this->module, $request, 'api-request');
+ $stubReplaces['resource'] = class_basename($resourceClass);
+ $stubReplaces['resourceNamespace'] = $this->getNamespaceOfClass($resourceClass);
+
+ if (in_array($stub, ['list', 'view'], true)) {
+ $wizardClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'wizard',
+ question: 'Enter the class name of the query wizard to be used in the action',
+ componentType: ModuleComponentType::ApiQueryWizard,
+ module: $this->module
+ );
+ $stubReplaces['queryWizard'] = class_basename($wizardClass);
+ $stubReplaces['queryWizardNamespace'] = $this->getNamespaceOfClass($wizardClass);
+ }
}
- return Stub::create("action/{$this->stub}.stub", $stubReplaces)->render();
+ $modelClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'model',
+ question: 'Enter the class name of the model to be used in the action',
+ componentType: ModuleComponentType::Model,
+ module: $this->module
+ );
+ $stubReplaces['model'] = class_basename($modelClass);
+ $stubReplaces['modelCamelCase'] = Str::camel($stubReplaces['model']);
+ $stubReplaces['modelNamespace'] = $this->getNamespaceOfClass($modelClass);
+
+ $requestClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'request',
+ question: 'Enter the class name of the request to be used in the action',
+ componentType: ModuleComponentType::ApiRequest,
+ module: $this->module
+ );
+ $stubReplaces['request'] = class_basename($requestClass);
+ $stubReplaces['requestNamespace'] = $this->getNamespaceOfClass($requestClass);
+
+ return $stubReplaces;
}
}
diff --git a/src/Commands/Generators/BaseComponentGeneratorCommand.php b/src/Commands/Generators/BaseComponentGeneratorCommand.php
new file mode 100755
index 0000000..3aabbfa
--- /dev/null
+++ b/src/Commands/Generators/BaseComponentGeneratorCommand.php
@@ -0,0 +1,474 @@
+beforeGenerate();
+
+ try {
+ $this->nameArgument = $this->argument('name');
+ $this->ensureNameIsNotReserved($this->nameArgument);
+ $this->ensureNameIsValidClassName($this->nameArgument);
+ $this->module = $this->getModuleArgumentOrFail();
+ } catch (NameIsReserved|InvalidClassName|ModuleNotFound|ModuleHasNonUniquePackageName|ModuleHasNoNamespace $exception) {
+ $this->components->error($exception->getMessage());
+
+ return self::FAILURE;
+ }
+
+ try {
+ $result = $this->generate(
+ $this->getGeneratedFilePath(),
+ $this->getContents(),
+ $this->option('force')
+ );
+ } catch (InvalidTableName $exception) {
+ $this->components->error($exception->getMessage());
+
+ return self::FAILURE;
+ }
+
+ if ($result !== self::SUCCESS) {
+ return $result;
+ }
+
+ $this->afterGenerate();
+
+ return self::SUCCESS;
+ }
+
+ /**
+ * Hook called before generation starts.
+ * Override in subclasses to add custom logic (e.g., package checks).
+ */
+ protected function beforeGenerate(): void
+ {
+ // Default: do nothing
+ }
+
+ /**
+ * Get the contents for the generated file.
+ * Must be implemented by subclasses.
+ */
+ abstract protected function getContents(): string;
+
+ /**
+ * Get the path for the generated file.
+ * Override in subclasses to customize (e.g., MigrationMakeCommand).
+ */
+ protected function getGeneratedFilePath(): string
+ {
+ return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
+ }
+
+ /**
+ * Hook called after successful generation.
+ * Override in subclasses to add custom logic (e.g., ProviderMakeCommand).
+ */
+ protected function afterGenerate(): void
+ {
+ // Default: do nothing
+ }
+
+ /**
+ * @param string $name
+ * @return void
+ *
+ * @throws NameIsReserved
+ */
+ protected function ensureNameIsNotReserved(string $name): void
+ {
+ $classBaseName = class_basename($name);
+
+ if ($this->isReservedName($classBaseName)) {
+ throw NameIsReserved::make($classBaseName);
+ }
+ }
+
+ /**
+ * Validate that the name is a valid PHP class name.
+ *
+ * @throws InvalidClassName
+ */
+ protected function ensureNameIsValidClassName(string $name): void
+ {
+ $classBaseName = class_basename($name);
+
+ if (! $this->isValidClassName($classBaseName)) {
+ throw InvalidClassName::make($classBaseName);
+ }
+ }
+
+ /**
+ * Check if the name is a valid PHP class name.
+ */
+ protected function isValidClassName(string $name): bool
+ {
+ // PHP class names must start with a letter or underscore,
+ // followed by any number of letters, numbers, or underscores.
+ // Also supports multibyte characters as per PHP specification.
+ return (bool) preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $name);
+ }
+
+ /**
+ * Check if the name is a valid database table name.
+ */
+ protected function isValidTableName(string $name): bool
+ {
+ // Table names should contain only letters, numbers, and underscores,
+ // and start with a letter or underscore.
+ return (bool) preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $name);
+ }
+
+ /**
+ * Generate component file.
+ * @return int The function returns "0" on success and "1" on failure.
+ */
+ protected function generate(string $path, string $contents, bool $force = false): int
+ {
+ if ($force === false && $this->filesystem->exists($path)) {
+ $this->components->error("File already exists: `$path`. Use --force to overwrite.");
+
+ return self::FAILURE;
+ }
+
+ $path = str_replace('\\', '/', $path);
+ $contents = $this->sortImports($contents);
+
+ $directory = dirname($path);
+
+ try {
+ $this->filesystem->ensureDirectoryExists($directory);
+ } catch (\Exception $e) {
+ $this->components->error("Failed to create directory: `$directory`. " . $e->getMessage());
+
+ return self::FAILURE;
+ }
+
+ if (! is_writable($directory)) {
+ $this->components->error("Directory is not writable: `$directory`. Check file permissions.");
+
+ return self::FAILURE;
+ }
+
+ if ($this->filesystem->put($path, $contents) !== false) {
+ $this->components->info("Created: `$path`");
+
+ return self::SUCCESS;
+ }
+
+ $this->components->error("Failed to write file: `$path`. Check disk space and file permissions.");
+
+ return self::FAILURE;
+ }
+
+ /**
+ * Get full class name from option or ask
+ */
+ public function getFullClassFromOptionOrAsk(
+ string $optionName,
+ string $question,
+ ModuleComponentType $componentType,
+ Module $module
+ ): string {
+ return $this->getFullClass(
+ $this->getOptionOrAsk(
+ $optionName,
+ $question,
+ ),
+ GeneratorHelper::component($componentType)->getFullNamespace($module)
+ );
+ }
+
+ /**
+ * Get full class name with namespace
+ */
+ public function getFullClass(string $class, string $defaultNamespace): string
+ {
+ if (Str::startsWith($class, '\\')) {
+ return $class;
+ }
+
+ return trim($defaultNamespace, '\\') . '\\' . trim($class, '\\');
+ }
+
+ /**
+ * Get the class "namespace" of the given class.
+ */
+ protected function getNamespaceOfClass(string $class): string
+ {
+ if (! Str::contains($class, '\\')) {
+ return '';
+ }
+
+ return rtrim(Str::beforeLast($class, '\\'), '\\');
+ }
+
+ /**
+ * Get component namespace, without the class name.
+ */
+ protected function getComponentNamespace(Module $module, string $name, ModuleComponentType $componentType): string
+ {
+ $name = str_replace('/', '\\', $name);
+ $componentNamespace = GeneratorHelper::component($componentType)->getFullNamespace($module);
+ $subNamespace = $this->getNamespaceOfClass($name);
+
+ $namespace = $componentNamespace . '\\' . $subNamespace;
+
+ return trim($namespace, '\\');
+ }
+
+ /**
+ * Get component path
+ */
+ protected function getComponentPath(
+ Module $module,
+ string $name,
+ ModuleComponentType $componentType,
+ string $extension = '.php'
+ ): string {
+ $componentPath = GeneratorHelper::component($componentType)->getFullPath($module);
+ $fileName = GeneratorHelper::normalizePath($name);
+
+ return $componentPath . '/' . $fileName . $extension;
+ }
+
+ protected function getUserModelClass(): string
+ {
+ $userModel = GeneratorHelper::getUserModelClass();
+
+ if (! $userModel) {
+ $userModel = $this->ask('Enter the class name of the "User model"');
+
+ if (empty($userModel)) {
+ throw new LogicException('The "User model" option is required');
+ }
+ }
+
+ return $userModel;
+ }
+
+ protected function getCreatePermissionActionClass(): string
+ {
+ $createPermissionAction = GeneratorHelper::getCreatePermissionActionClass();
+
+ if (! $createPermissionAction) {
+ $createPermissionAction = $this->ask('Enter the class name of the "Create permission action"');
+
+ if (empty($createPermissionAction)) {
+ throw new LogicException('The "Create permission action" option is required');
+ }
+ }
+
+ return $createPermissionAction;
+ }
+
+ protected function getCreatePermissionDTOClass(): string
+ {
+ $createPermissionAction = GeneratorHelper::getCreatePermissionDTOClass();
+
+ if (! $createPermissionAction) {
+ $createPermissionAction = $this->ask('Enter the class name of the "Create permission DTO"');
+
+ if (empty($createPermissionAction)) {
+ throw new LogicException('The "Create permission DTO" option is required');
+ }
+ }
+
+ return $createPermissionAction;
+ }
+
+ /**
+ * Checks whether the given name is reserved.
+ */
+ protected function isReservedName(string $name): bool
+ {
+ $name = strtolower($name);
+
+ return in_array($name, $this->reservedNames, true);
+ }
+
+ /**
+ * Alphabetically sorts the imports for the given stub.
+ */
+ protected function sortImports(string $stubContent): string
+ {
+ if (preg_match('/(?P(?:use [^;]+;$\n?)+)/m', $stubContent, $match)) {
+ $imports = explode("\n", trim($match['imports']));
+
+ sort($imports);
+ $imports = array_unique($imports);
+
+ return str_replace(trim($match['imports']), implode("\n", $imports), $stubContent);
+ }
+
+ return $stubContent;
+ }
+
+ /**
+ * Get the first view directory path from the application configuration.
+ */
+ protected function viewPath(string $path = ''): string
+ {
+ $views = $this->laravel['config']['view.paths'][0] ?? resource_path('views');
+
+ return $views.($path ? DIRECTORY_SEPARATOR.$path : $path);
+ }
+
+ /**
+ * Check if the package is installed
+ */
+ protected function packageIsInstalled(string $packageName): bool
+ {
+ $vendorPath = Env::get('COMPOSER_VENDOR_DIR') ?: $this->laravel->basePath('/vendor');
+ $installedJsonPath = $vendorPath . '/composer/installed.json';
+
+ if (! $this->filesystem->exists($installedJsonPath)) {
+ return false;
+ }
+
+ /** @var array{packages?: array} $installed */
+ $installed = json_decode($this->filesystem->get($installedJsonPath), true);
+
+ foreach ($installed['packages'] ?? [] as $package) {
+ if ($package['name'] === $packageName) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected function ensurePackageIsInstalledOrWarn(string $packageName): void
+ {
+ if ($this->packageIsInstalled($packageName)) {
+ $this->components->warn("Package '$packageName' is not installed!");
+ $this->components->warn("Please install by entering `composer require $packageName` on the command line");
+ }
+ }
+}
diff --git a/src/Commands/Generators/CommandMakeCommand.php b/src/Commands/Generators/CommandMakeCommand.php
index e049b51..d085dbd 100644
--- a/src/Commands/Generators/CommandMakeCommand.php
+++ b/src/Commands/Generators/CommandMakeCommand.php
@@ -2,89 +2,70 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class CommandMakeCommand extends ComponentGeneratorCommand
+class CommandMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:command';
+ protected $signature = 'module:make:command
+ {name : The name of the command class}
+ {module? : The name or package name of the app module}
+ {--s|signature= : The signature of the console command}
+ {--description= : The console command description}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new Artisan command for the specified module.';
+ protected $description = 'Generate new artisan command for the specified module.';
/**
- * Module instance.
- *
- * @var Module
+ * The module component type.
*/
- protected Module $module;
+ protected ModuleComponentType $componentType = ModuleComponentType::CliCommand;
/**
- * Component type.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $componentType = 'cli-command';
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
- */
- protected string $nameArgument;
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['command', 'c', InputOption::VALUE_REQUIRED, 'The terminal command that should be assigned.'],
+ 'name' => 'Enter the command class name',
];
}
- protected function prepare()
- {
- $this->module = $this->getModule();
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
+ protected function getContents(): string
{
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
- {
- $command = $this->getOptionOrAsk(
- 'command',
- 'Enter the terminal command that should be assigned',
- 'command:name',
- true
+ $signature = $this->getOptionOrAsk(
+ 'signature',
+ 'Enter the console command signature that should be assigned'
+ );
+ $description = $this->getOptionOrAsk(
+ 'description',
+ 'Enter the console command description',
+ '',
+ false
);
-
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument),
- 'command' => $command
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
+ 'signature' => $signature,
+ 'description' => $description,
];
return Stub::create("command.stub", $stubReplaces)->render();
diff --git a/src/Commands/Generators/ComponentGeneratorCommand.php b/src/Commands/Generators/ComponentGeneratorCommand.php
deleted file mode 100755
index 979eafb..0000000
--- a/src/Commands/Generators/ComponentGeneratorCommand.php
+++ /dev/null
@@ -1,338 +0,0 @@
-prepare();
-
- // First we need to ensure that the given name is not a reserved word within the PHP
- // language and that the class name will actually be valid. If it is not valid we
- // can error now and prevent from polluting the filesystem using invalid files.
- if ($this->isReservedName($this->getClass($this->getTrimmedArgument('name')))) {
- $this->error('The name "'.$this->getClass($this->getTrimmedArgument('name')).'" is reserved by PHP.');
-
- return self::FAILURE;
- }
-
- $path = str_replace('\\', '/', $this->getDestinationFilePath());
- $contents = $this->sortImports($this->getTemplateContents());
-
- try {
- $overwriteFile = $this->hasOption('force') && $this->option('force');
-
- File::ensureDirectoryExists(dirname($path));
- (new FileGenerator($path, $contents))->withFileOverwrite($overwriteFile)->generate();
-
- $this->info("Created: `$path`");
- } catch (FileAlreadyExistException $e) {
- $this->error("File: `$path` already exists.");
-
- return self::FAILURE;
- }
-
- return self::SUCCESS;
- }
-
- /**
- * Get the class "basename" of the given class.
- *
- * @param string $class
- *
- * @return string
- */
- protected function getClass(string $class): string
- {
- return class_basename($class);
- }
-
- /**
- * Get the class "namespace" of the given class.
- *
- * @param string $class
- *
- * @return string
- */
- protected function getNamespaceOfClass(string $class): string
- {
- if (! Str::contains($class, '\\')) {
- return '';
- }
-
- return rtrim(Str::beforeLast($class, '\\'), '\\');
- }
-
- /**
- * Get component namespace, without the class name.
- *
- * @param Module $module
- * @param string $name
- * @param string $componentType
- *
- * @return string
- */
- protected function getComponentNamespace(Module $module, string $name, string $componentType): string
- {
- $name = str_replace('/', '\\', $name);
- $componentNamespace = GeneratorHelper::component($componentType)->getFullNamespace($module);
- $extraNamespace = $this->getNamespaceOfClass($name);
-
- $namespace = $componentNamespace . '\\' . $extraNamespace;
-
- return trim($namespace, '\\');
- }
-
- /**
- * Get component path, without the extension.
- *
- * @param Module $module
- * @param string $name
- * @param string $componentType
- * @param string $extension
- * @return string
- */
- protected function getComponentPath(
- Module $module,
- string $name,
- string $componentType,
- string $extension = '.php'
- ): string {
- $componentPath = GeneratorHelper::component($componentType)->getFullPath($module);
- $fileName = $this->convertNamespaceToPath($name);
-
- return $componentPath . '/' . $fileName . $extension;
- }
-
- /**
- * @return string
- */
- protected function getUserModelClass(): string
- {
- $userModel = GeneratorHelper::userModel();
-
- if (!$userModel) {
- $userModel = $this->ask('Enter the class name of the "User model"');
-
- if (empty($userModel)) {
- throw new LogicException('The "User model" option is required');
- }
- }
-
- return $userModel;
- }
-
- /**
- * @return string
- */
- protected function getCreatePermissionActionClass(): string
- {
- $createPermissionAction = GeneratorHelper::createPermissionAction();
-
- if (!$createPermissionAction) {
- $createPermissionAction = $this->ask('Enter the class name of the "Create permission action"');
-
- if (empty($createPermissionAction)) {
- throw new LogicException('The "Create permission action" option is required');
- }
- }
-
- return $createPermissionAction;
- }
-
- /**
- * @return string
- */
- protected function getCreatePermissionDTOClass(): string
- {
- $createPermissionAction = GeneratorHelper::createPermissionDTO();
-
- if (!$createPermissionAction) {
- $createPermissionAction = $this->ask('Enter the class name of the "Create permission DTO"');
-
- if (empty($createPermissionAction)) {
- throw new LogicException('The "Create permission DTO" option is required');
- }
- }
-
- return $createPermissionAction;
- }
-
- /**
- * Convert namespace to path
- *
- * @param string $namespace
- *
- * @return string
- */
- protected function convertNamespaceToPath(string $namespace): string
- {
- return trim(str_replace('\\', '/', $namespace), '/');
- }
-
- /**
- * Checks whether the given name is reserved.
- *
- * @param string $name
- * @return bool
- */
- protected function isReservedName(string $name): bool
- {
- $name = strtolower($name);
-
- return in_array($name, $this->reservedNames, true);
- }
-
- /**
- * Alphabetically sorts the imports for the given stub.
- *
- * @param string $stubContent
- *
- * @return string
- */
- protected function sortImports(string $stubContent): string
- {
- if (preg_match('/(?P(?:use [^;]+;$\n?)+)/m', $stubContent, $match)) {
- $imports = explode("\n", trim($match['imports']));
-
- sort($imports);
- $imports = array_unique($imports);
-
- return str_replace(trim($match['imports']), implode("\n", $imports), $stubContent);
- }
-
- return $stubContent;
- }
-}
diff --git a/src/Commands/Generators/ComponentsMakeCommand.php b/src/Commands/Generators/ComponentsMakeCommand.php
deleted file mode 100644
index 09d599d..0000000
--- a/src/Commands/Generators/ComponentsMakeCommand.php
+++ /dev/null
@@ -1,88 +0,0 @@
-argument('name');
- $entityName = $this->option('entity');
- $module = Modules::findOrFail($name);
-
- $code = (new ModuleComponentsGenerator($module))
- ->setEntityName($entityName ?: $name)
- ->setType($this->getModuleType())
- ->setConsole($this)
- ->generate();
-
- if ($code === E_ERROR) {
- return self::FAILURE;
- }
-
- return self::SUCCESS;
- }
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['name', InputArgument::REQUIRED, 'The name of the module.'],
- ];
- }
-
- protected function getOptions(): array
- {
- return [
-// ['api', 'a', InputOption::VALUE_NONE, 'Generate an api module (with api components, enabled by default).'],
-// ['web', 'w', InputOption::VALUE_NONE, 'Generate a web module (with web components).'],
- ['entity', null, InputOption::VALUE_REQUIRED, 'Entity name (used to create module components, the default is the name of the module).'],
- ];
- }
-
- /**
- * Get module type.
- *
- * @return string
- */
- private function getModuleType(): string
- {
-// if ($this->option('web')) {
-// return 'web';
-// }
-
- return 'api';
- }
-}
diff --git a/src/Commands/Generators/ControllerMakeCommand.php b/src/Commands/Generators/ControllerMakeCommand.php
index c137dc9..d5fa285 100644
--- a/src/Commands/Generators/ControllerMakeCommand.php
+++ b/src/Commands/Generators/ControllerMakeCommand.php
@@ -2,24 +2,25 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class ControllerMakeCommand extends ComponentGeneratorCommand
+class ControllerMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:controller';
+ protected $signature = 'module:make:controller
+ {name : The name of the controller class}
+ {module? : The name or package name of the app module}
+ {--ui= : The UI for which the controller will be created}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -29,68 +30,39 @@ class ControllerMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new controller for the specified module.';
/**
- * The UI for which the request will be created.
- *
- * @var string
+ * The UI for which the controller will be created.
+ * ('web' or 'api')
*/
- protected string $ui = 'api';
+ protected string $ui;
/**
- * Module instance.
- *
- * @var Module
+ * Prompt for missing input arguments using the returned questions.
*/
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
- */
- protected string $nameArgument;
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['ui', null, InputOption::VALUE_REQUIRED, 'The UI for which the request will be created.'],
+ 'name' => 'Enter the controller class name',
];
}
- protected function prepare()
+ protected function beforeGenerate(): void
{
- $this->module = $this->getModule();
$this->ui = $this->getOptionOrChoice(
'ui',
- 'Select UI for which the request will be created',
- ['api', 'web'],
- 'api'
+ question: 'Enter the UI for which the controller will be created',
+ choices: ['api', 'web'],
+ default: 'api'
);
- $this->componentType = "{$this->ui}-controller";
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
+ $this->componentType = $this->ui === 'api'
+ ? ModuleComponentType::ApiController
+ : ModuleComponentType::WebController;
}
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
$stubReplaces = [
'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'class' => class_basename($this->nameArgument),
];
return Stub::create("controller/{$this->ui}.stub", $stubReplaces)->render();
diff --git a/src/Commands/Generators/DTOMakeCommand.php b/src/Commands/Generators/DTOMakeCommand.php
index dbb8f2b..fc7457e 100644
--- a/src/Commands/Generators/DTOMakeCommand.php
+++ b/src/Commands/Generators/DTOMakeCommand.php
@@ -2,23 +2,24 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class DTOMakeCommand extends ComponentGeneratorCommand
+class DTOMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:dto';
+ protected $signature = 'module:make:dto
+ {name : The name of the DTO class}
+ {module? : The name or package name of the app module}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -28,54 +29,36 @@ class DTOMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new DTO for the specified module.';
/**
- * Module instance.
- *
- * @var Module
+ * The module component type.
*/
- protected Module $module;
+ protected ModuleComponentType $componentType = ModuleComponentType::Dto;
/**
- * Component type.
- *
- * @var string
- */
- protected string $componentType = 'dto';
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $nameArgument;
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
- return [];
- }
-
- protected function prepare()
- {
- $this->module = $this->getModule();
- $this->nameArgument = $this->getTrimmedArgument('name');
+ return [
+ 'name' => 'Enter the DTO class name',
+ ];
}
- protected function getDestinationFilePath(): string
+ protected function beforeGenerate(): void
{
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
+ $this->ensurePackageIsInstalledOrWarn('spatie/laravel-data');
}
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
- return Stub::create("dto/default.stub", $stubReplaces)->render();
+ return Stub::create("dto.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/EventMakeCommand.php b/src/Commands/Generators/EventMakeCommand.php
index 85f4eec..612963e 100644
--- a/src/Commands/Generators/EventMakeCommand.php
+++ b/src/Commands/Generators/EventMakeCommand.php
@@ -2,68 +2,56 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class EventMakeCommand extends ComponentGeneratorCommand
+class EventMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:event';
+ protected $signature = 'module:make:event
+ {name : The name of the event class}
+ {module? : The name or package name of the app module}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new event for the specified module.';
+ protected $description = 'Generate new event class for the specified module.';
/**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
+ * The module component type.
*/
- protected string $componentType = 'event';
+ protected ModuleComponentType $componentType = ModuleComponentType::Event;
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $nameArgument;
-
- protected function prepare()
+ protected function promptForMissingArgumentsUsing(): array
{
- $this->module = $this->getModule();
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
+ return [
+ 'name' => 'Enter the event class name',
+ ];
}
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument),
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
return Stub::create("event.stub", $stubReplaces)->render();
diff --git a/src/Commands/Generators/ExceptionMakeCommand.php b/src/Commands/Generators/ExceptionMakeCommand.php
index 3e57409..d4f77e8 100644
--- a/src/Commands/Generators/ExceptionMakeCommand.php
+++ b/src/Commands/Generators/ExceptionMakeCommand.php
@@ -2,68 +2,56 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class ExceptionMakeCommand extends ComponentGeneratorCommand
+class ExceptionMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:exception';
+ protected $signature = 'module:make:exception
+ {name : The name of the exception class}
+ {module? : The name or package name of the app module}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new exception for the specified module.';
+ protected $description = 'Generate new exception class for the specified module.';
/**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
+ * The module component type.
*/
- protected string $componentType = 'exception';
+ protected ModuleComponentType $componentType = ModuleComponentType::Exception;
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $nameArgument;
-
- protected function prepare()
+ protected function promptForMissingArgumentsUsing(): array
{
- $this->module = $this->getModule();
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
+ return [
+ 'name' => 'Enter the exception class name',
+ ];
}
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument),
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
return Stub::create("exception.stub", $stubReplaces)->render();
diff --git a/src/Commands/Generators/FactoryMakeCommand.php b/src/Commands/Generators/FactoryMakeCommand.php
index 12948b5..1537e65 100644
--- a/src/Commands/Generators/FactoryMakeCommand.php
+++ b/src/Commands/Generators/FactoryMakeCommand.php
@@ -2,25 +2,26 @@
namespace Laraneat\Modules\Commands\Generators;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Str;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class FactoryMakeCommand extends ComponentGeneratorCommand
+class FactoryMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:factory';
+ protected $signature = 'module:make:factory
+ {name : The name of the factory class}
+ {module? : The name or package name of the app module}
+ {--model= : The class name of the model to be used in the factory}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -30,64 +31,38 @@ class FactoryMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new factory for the specified module.';
/**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
+ * The module component type.
*/
- protected string $componentType = 'factory';
+ protected ModuleComponentType $componentType = ModuleComponentType::Factory;
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $nameArgument;
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['model', null, InputOption::VALUE_REQUIRED, 'The class name of the model to be used in the factory.'],
+ 'name' => 'Enter the factory class name',
];
}
- protected function prepare()
- {
- $this->module = $this->getModule();
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
- $model = $this->getOptionOrAsk(
- 'model',
- 'Enter the class name of the model to be used in the factory',
- '',
- true
+ $modelClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'model',
+ question: 'Enter the class name of the model to be used in the factory',
+ componentType: ModuleComponentType::Model,
+ module: $this->module
);
- $modelClass = $this->getClass($model);
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument),
- 'model' => $modelClass,
- 'modelEntity' => Str::camel($modelClass),
- 'modelNamespace' => $this->getComponentNamespace($this->module, $model, 'model')
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
+ 'model' => class_basename($modelClass),
+ 'modelCamelCase' => Str::camel(class_basename($modelClass)),
+ 'modelNamespace' => $this->getNamespaceOfClass($modelClass),
];
return Stub::create("factory.stub", $stubReplaces)->render();
diff --git a/src/Commands/Generators/JobMakeCommand.php b/src/Commands/Generators/JobMakeCommand.php
index 3a9fe90..27beb39 100644
--- a/src/Commands/Generators/JobMakeCommand.php
+++ b/src/Commands/Generators/JobMakeCommand.php
@@ -2,97 +2,65 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class JobMakeCommand extends ComponentGeneratorCommand
+class JobMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:job';
+ protected $signature = 'module:make:job
+ {name : The name of the job class}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new job for the specified module.';
-
- /**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'plain';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
+ protected $description = 'Generate new job class for the specified module.';
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * The module component type.
*/
- protected string $nameArgument;
+ protected ModuleComponentType $componentType = ModuleComponentType::Job;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
+ 'name' => 'Enter the job class name',
];
}
- protected function prepare()
+ protected function getContents(): string
{
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
+ $stub = $this->getOptionOrChoice(
'stub',
'Select the stub you want to use for generator',
['plain', 'queued'],
'plain'
);
- $this->componentType = 'job';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
- {
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
- return Stub::create("job/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("job/$stub.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/ListenerMakeCommand.php b/src/Commands/Generators/ListenerMakeCommand.php
index 7301d0d..cd1dfb0 100644
--- a/src/Commands/Generators/ListenerMakeCommand.php
+++ b/src/Commands/Generators/ListenerMakeCommand.php
@@ -2,107 +2,74 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class ListenerMakeCommand extends ComponentGeneratorCommand
+class ListenerMakeCommand extends BaseComponentGeneratorCommand
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:listener';
+ protected $signature = 'module:make:listener
+ {name : The name of the listener class}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--event= : The class name of the event to listen to}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new listener for the specified module.';
-
- /**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'plain';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
+ protected $description = 'Generate new listener class for the specified module.';
/**
- * Prepared 'name' argument
- *
- * @var string
+ * The module component type.
*/
- protected string $nameArgument;
+ protected ModuleComponentType $componentType = ModuleComponentType::Listener;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
- ['event', null, InputOption::VALUE_REQUIRED, 'The class name of the event to listen to.'],
+ 'name' => 'Enter the listener class name',
];
}
- protected function prepare()
+ protected function getContents(): string
{
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
+ $stub = $this->getOptionOrChoice(
'stub',
'Select the stub you want to use for generator',
['plain', 'queued'],
'plain'
);
- $this->componentType = 'listener';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
- {
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument),
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
- $event = $this->getOptionOrAsk(
- 'event',
- 'Enter the class name of the event that will be listened to',
- '',
- true
+ $eventClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'event',
+ question: 'Enter the class name of the event to listen to',
+ componentType: ModuleComponentType::Event,
+ module: $this->module
);
- $stubReplaces['event'] = $this->getClass($event);
- $stubReplaces['eventNamespace'] = $this->getComponentNamespace($this->module, $event, 'event');
+ $stubReplaces['event'] = class_basename($eventClass);
+ $stubReplaces['eventNamespace'] = $this->getNamespaceOfClass($eventClass);
- return Stub::create("listener/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("listener/$stub.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/MailMakeCommand.php b/src/Commands/Generators/MailMakeCommand.php
index 833e514..3dda291 100644
--- a/src/Commands/Generators/MailMakeCommand.php
+++ b/src/Commands/Generators/MailMakeCommand.php
@@ -2,97 +2,75 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Illuminate\Support\Str;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class MailMakeCommand extends ComponentGeneratorCommand
+class MailMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:mail';
+ protected $signature = 'module:make:mail
+ {name : The name of the mail class}
+ {module? : The name or package name of the app module}
+ {--subject= : The subject of mail}
+ {--view= : The view for the mail}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new mail for the specified module.';
-
- /**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'plain';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
+ protected $description = 'Generate new mail class for the specified module.';
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * The module component type.
*/
- protected string $nameArgument;
+ protected ModuleComponentType $componentType = ModuleComponentType::Mail;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
+ 'name' => 'Enter the mail class name',
];
}
- protected function prepare()
+ protected function getContents(): string
{
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
- 'stub',
- 'Select the stub you want to use for generator',
- ['plain', 'queued'],
- 'plain'
+ $classBaseName = class_basename($this->nameArgument);
+ $subject = $this->getOptionOrAsk(
+ "subject",
+ "Enter the subject of mail",
+ Str::headline($classBaseName)
+ );
+ $view = $this->getOptionOrAsk(
+ "view",
+ "Enter the view for the mail",
+ 'view.name'
);
- $this->componentType = 'mail';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
- protected function getTemplateContents(): string
- {
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => $classBaseName,
+ 'subject' => $subject,
+ 'view' => $view,
];
- return Stub::create("mail/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("mail.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/MiddlewareMakeCommand.php b/src/Commands/Generators/MiddlewareMakeCommand.php
index 0befdd1..84dc4ae 100644
--- a/src/Commands/Generators/MiddlewareMakeCommand.php
+++ b/src/Commands/Generators/MiddlewareMakeCommand.php
@@ -2,68 +2,56 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class MiddlewareMakeCommand extends ComponentGeneratorCommand
+class MiddlewareMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:middleware';
+ protected $signature = 'module:make:middleware
+ {name : The name of the middleware class}
+ {module? : The name or package name of the app module}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new middleware for the specified module.';
+ protected $description = 'Generate new middleware class for the specified module.';
/**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
+ * The module component type.
*/
- protected string $componentType = 'middleware';
+ protected ModuleComponentType $componentType = ModuleComponentType::Middleware;
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $nameArgument;
-
- protected function prepare()
+ protected function promptForMissingArgumentsUsing(): array
{
- $this->module = $this->getModule();
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
+ return [
+ 'name' => 'Enter the middleware class name',
+ ];
}
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument),
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
return Stub::create("middleware.stub", $stubReplaces)->render();
diff --git a/src/Commands/Generators/MigrationMakeCommand.php b/src/Commands/Generators/MigrationMakeCommand.php
index 5dad12d..9e17aa5 100644
--- a/src/Commands/Generators/MigrationMakeCommand.php
+++ b/src/Commands/Generators/MigrationMakeCommand.php
@@ -2,29 +2,33 @@
namespace Laraneat\Modules\Commands\Generators;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Str;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Generator\GeneratorHelper;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Exceptions\InvalidTableName;
+use Laraneat\Modules\Support\Generator\Stub;
use Laraneat\Modules\Support\Migrations\NameParser;
use Laraneat\Modules\Support\Migrations\SchemaParser;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
use LogicException;
-use Symfony\Component\Console\Input\InputOption;
/**
* @group generator
*/
-class MigrationMakeCommand extends ComponentGeneratorCommand
+class MigrationMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:migration';
+ protected $signature = 'module:make:migration
+ {name : The name of the migration}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--f|fields= : The specified fields table}
+ {--t1|tableOne= : The name of first table}
+ {--t2|tableTwo= : The name of second table}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -34,77 +38,45 @@ class MigrationMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new migration for the specified module.';
/**
- * The stub name to load for this generator.
- *
- * @var string|null
- */
- protected ?string $stub = null;
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
+ * The module component type.
*/
- protected string $componentType;
+ protected ModuleComponentType $componentType = ModuleComponentType::Migration;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.', ''],
- ['fields', 'f', InputOption::VALUE_REQUIRED, 'The specified fields table.', null],
- ['tableOne', 't1', InputOption::VALUE_REQUIRED, 'The name of first table.'],
- ['tableTwo', 't2', InputOption::VALUE_REQUIRED, 'The name of second table.'],
+ 'name' => 'Enter the migration name',
];
}
- protected function getSchemaParser(): SchemaParser
+ protected function getGeneratedFilePath(): string
{
- return new SchemaParser($this->option('fields'));
+ return $this->getComponentPath($this->module, $this->getFileName(), $this->componentType);
}
- protected function getFileName(): string
+ protected function getContents(): string
{
- return date('Y_m_d_His_') . Str::snake($this->getTrimmedArgument('name'));
- }
-
- protected function prepare()
- {
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOneOf(
+ $stub = $this->getOptionOneOf(
'stub',
- ['', 'plain', 'add', 'create', 'delete', 'pivot'],
+ choices: [
+ null,
+ 'add',
+ 'create',
+ 'delete',
+ 'pivot',
+ 'plain',
+ ],
);
- $this->componentType = 'migration';
- }
-
- protected function getDestinationFilePath(): string
- {
- $componentPath = GeneratorHelper::component($this->componentType)->getFullPath($this->module);
-
- return $componentPath . '/' . $this->getFileName() . '.php';
- }
-
- protected function getTemplateContents(): string
- {
$parser = new NameParser($this->argument('name'));
- if ($this->stub === 'pivot') {
+ if ($stub === 'pivot') {
return $this->generatePivotMigrationContent($parser);
}
- if ($this->stub === 'add' || (empty($this->stub) && $parser->isAdd())) {
+ if ($stub === 'add' || (empty($stub) && $parser->isAdd())) {
return Stub::create('/migration/add.stub', [
'table' => $this->getTableName($parser),
'fieldsUp' => $this->getSchemaParser()->up(),
@@ -112,14 +84,14 @@ protected function getTemplateContents(): string
])->render();
}
- if ($this->stub === 'create' || (empty($this->stub) && $parser->isCreate())) {
+ if ($stub === 'create' || (empty($stub) && $parser->isCreate())) {
return Stub::create('/migration/create.stub', [
'table' => $this->getTableName($parser),
'fields' => $this->getSchemaParser()->render(),
])->render();
}
- if ($this->stub === 'delete' || (empty($this->stub) && $parser->isDelete())) {
+ if ($stub === 'delete' || (empty($stub) && $parser->isDelete())) {
return Stub::create('/migration/delete.stub', [
'table' => $this->getTableName($parser),
'fieldsDown' => $this->getSchemaParser()->up(),
@@ -130,6 +102,9 @@ protected function getTemplateContents(): string
return Stub::create('/migration/plain.stub')->render();
}
+ /**
+ * @throws InvalidTableName
+ */
protected function getTableName(NameParser $parser): string
{
$tableName = $parser->getTableName();
@@ -142,9 +117,16 @@ protected function getTableName(NameParser $parser): string
}
}
+ if (! $this->isValidTableName($tableName)) {
+ throw InvalidTableName::make($tableName);
+ }
+
return $tableName;
}
+ /**
+ * @throws InvalidTableName
+ */
protected function generatePivotMigrationContent(NameParser $parser): string
{
$table = $this->getTableName($parser);
@@ -157,26 +139,42 @@ protected function generatePivotMigrationContent(NameParser $parser): string
$tableOne = $this->getOptionOrAsk(
'tableOne',
- 'Enter the name of first table.',
- $tableOne ?? '',
- true
+ 'Enter the name of first table',
+ $tableOne ?? ''
);
$tableTwo = $this->getOptionOrAsk(
'tableTwo',
- 'Enter the name of second table.',
- $tableTwo ?? '',
- true
+ 'Enter the name of second table',
+ $tableTwo ?? ''
);
+ if (! $this->isValidTableName($tableOne)) {
+ throw InvalidTableName::make($tableOne);
+ }
+
+ if (! $this->isValidTableName($tableTwo)) {
+ throw InvalidTableName::make($tableTwo);
+ }
+
return Stub::create('/migration/pivot.stub', [
'table' => $table,
'tableOne' => $tableOne,
'tableTwo' => $tableTwo,
'columnOne' => $this->convertTableNameToPrimaryColumnName($tableOne),
- 'columnTwo' => $this->convertTableNameToPrimaryColumnName($tableTwo)
+ 'columnTwo' => $this->convertTableNameToPrimaryColumnName($tableTwo),
])->render();
}
+ protected function getSchemaParser(): SchemaParser
+ {
+ return new SchemaParser($this->option('fields'));
+ }
+
+ protected function getFileName(): string
+ {
+ return now()->format('Y_m_d_His_') . Str::snake($this->nameArgument);
+ }
+
protected function convertTableNameToPrimaryColumnName(string $tableName): string
{
return Str::singular($tableName) . '_id';
diff --git a/src/Commands/Generators/ModelMakeCommand.php b/src/Commands/Generators/ModelMakeCommand.php
index 7d45240..44cd497 100644
--- a/src/Commands/Generators/ModelMakeCommand.php
+++ b/src/Commands/Generators/ModelMakeCommand.php
@@ -2,24 +2,26 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\GeneratorHelper;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class ModelMakeCommand extends ComponentGeneratorCommand
+class ModelMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:model';
+ protected $signature = 'module:make:model
+ {name : The name of the model}
+ {module? : The name or package name of the app module}
+ {--factory= : The class name of the model factory}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -29,86 +31,46 @@ class ModelMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new model for the specified module.';
/**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'full';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
+ * The module component type.
*/
- protected string $componentType;
+ protected ModuleComponentType $componentType = ModuleComponentType::Model;
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $nameArgument;
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
- ['factory', null, InputOption::VALUE_REQUIRED, 'The class name of the model factory.'],
+ 'name' => 'Enter the model class name',
];
}
- protected function prepare()
- {
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
- 'stub',
- 'Select the stub you want to use for generator',
- ['plain', 'full'],
- 'full'
- );
- $this->componentType = 'model';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
+ $stub = 'plain';
$stubReplaces = [
'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'class' => class_basename($this->nameArgument),
];
- if ($this->stub === 'full') {
- $factory = $this->getOptionOrAsk(
- 'factory',
- 'Enter the class name of the model factory',
- ''
+ $factoryOption = $this->getOptionOrAsk(
+ 'factory',
+ question: 'Enter the class name of the factory to be used in the model (optional)',
+ required: false
+ );
+
+ if ($factoryOption) {
+ $factoryClass = $this->getFullClass(
+ $factoryOption,
+ GeneratorHelper::component(ModuleComponentType::Factory)
+ ->getFullNamespace($this->module)
);
- if ($factory) {
- $stubReplaces['factory'] = $this->getClass($factory);
- $stubReplaces['factoryNamespace'] = $this->getComponentNamespace($this->module, $factory, 'factory');
- } else {
- $this->stub = 'plain';
- }
+ $stub = 'full';
+ $stubReplaces['factory'] = class_basename($factoryClass);
+ $stubReplaces['factoryNamespace'] = $this->getNamespaceOfClass($factoryClass);
}
- return Stub::create("model/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("model/$stub.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/ModuleMakeCommand.php b/src/Commands/Generators/ModuleMakeCommand.php
index 03fd0b8..1c4bef0 100755
--- a/src/Commands/Generators/ModuleMakeCommand.php
+++ b/src/Commands/Generators/ModuleMakeCommand.php
@@ -2,23 +2,31 @@
namespace Laraneat\Modules\Commands\Generators;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Contracts\ActivatorInterface;
-use Laraneat\Modules\Generators\ModuleGenerator;
-use Symfony\Component\Console\Input\InputArgument;
-use Symfony\Component\Console\Input\InputOption;
+use Composer\Factory;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Illuminate\Support\Str;
+use Laraneat\Modules\Exceptions\ComposerException;
+use Laraneat\Modules\Module;
+use Laraneat\Modules\Support\Composer;
+use Laraneat\Modules\Support\ComposerJsonFile;
+use Laraneat\Modules\Support\Generator\GeneratorHelper;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class ModuleMakeCommand extends Command
+class ModuleMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
/**
- * The console command name.
+ * The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make';
+ protected $signature = 'module:make
+ {name : The name of the module to be created}
+ {--preset= : The preset of the module to be created ("plain", "base", or "api", "plain" by default)}
+ {--entity= : Entity name (used to create module components, the default is the name of the module)}
+ {--force : Overwrite the module if it already exists}';
/**
* The console command description.
@@ -27,74 +35,365 @@ class ModuleMakeCommand extends Command
*/
protected $description = 'Create a new module.';
+ /**
+ * The name of the module to be created
+ */
+ protected string $moduleName;
+
+ /**
+ * Studly name of the module to be created
+ */
+ protected string $moduleStudlyName;
+
+ /**
+ * The package name of the module to be created
+ */
+ protected string $modulePackageName;
+
+ /**
+ * The preset of the module to be created
+ */
+ protected string $modulePreset;
+
+ /**
+ * The entity name (used to create module components, the default is the name of the module)
+ */
+ protected ?string $entityName = null;
+
+ /**
+ * Prompt for missing input arguments using the returned questions.
+ */
+ protected function promptForMissingArgumentsUsing(): array
+ {
+ return [
+ 'name' => 'Enter the name of the module to be created',
+ ];
+ }
+
/**
* Execute the console command.
- *
- * @return int
*/
public function handle(): int
{
- $name = $this->argument('name');
- $entityName = $this->option('entity');
-
- $code = (new ModuleGenerator($name))
- ->setEntityName($entityName ?: $name)
- ->setFilesystem($this->laravel['files'])
- ->setRepository($this->laravel['modules'])
- ->setConfig($this->laravel['config'])
- ->setActivator($this->laravel[ActivatorInterface::class])
- ->setConsole($this)
- ->setForce($this->option('force'))
- ->setType($this->getModuleType())
- ->setActive(!$this->option('disabled'))
- ->generate();
-
- if ($code === E_ERROR) {
+ $nameArgument = trim($this->argument('name'), '/\\');
+ $explodedNameArgument = explode('/', $nameArgument, 2);
+
+ [$rawVendor, $rawModuleName] = empty($explodedNameArgument[1])
+ ? ['', $explodedNameArgument[0]]
+ : $explodedNameArgument;
+
+ $this->moduleStudlyName = Str::studly($rawModuleName);
+ $this->moduleName = Str::kebab($this->moduleStudlyName);
+ if (! $this->validateModuleStudlyName($this->moduleStudlyName)) {
+ $this->components->error("The module name passed is not valid!");
+
+ return self::FAILURE;
+ }
+
+ $this->modulePackageName = sprintf(
+ '%s/%s',
+ Str::kebab($rawVendor ?: config('modules.composer.vendor', 'app')),
+ $this->moduleName
+ );
+
+ if ($this->modulesRepository->has($this->modulePackageName)) {
+ $this->components->error("Module '$this->modulePackageName' already exist!");
+
+ return self::FAILURE;
+ }
+
+ $this->modulePreset = $this->getOptionOrChoice(
+ optionName: 'preset',
+ question: 'Select the preset of module to create',
+ choices: [
+ 'plain',
+ 'base',
+ 'api',
+ ],
+ default: 'plain'
+ );
+
+ if ($this->isFailure($this->generateComposerJsonFile())) {
+ return self::FAILURE;
+ }
+
+ $this->modulesRepository->pruneModulesManifest();
+
+ if ($this->isFailure($this->generateComponents($this->modulesRepository->find($this->modulePackageName)))) {
return self::FAILURE;
}
+ try {
+ $this->addModuleToComposer();
+ } catch (ComposerException $exception) {
+ $this->components->error($exception->getMessage());
+ $this->components->info("Please run composer update {$this->modulePackageName} manually");
+ }
+
return self::SUCCESS;
}
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
+ protected function addModuleToComposer(): void
{
- return [
- ['name', InputArgument::REQUIRED, 'The name of the module to be created.'],
- ];
+ $initialWorkingDir = getcwd();
+ $appBasePath = $this->laravel->basePath();
+ chdir($appBasePath);
+ $moduleRelativePath = GeneratorHelper::makeRelativePath($appBasePath, GeneratorHelper::makeModulePath($this->moduleName));
+ ComposerJsonFile::create(Factory::getComposerFile())
+ ->addModule($this->modulePackageName, $moduleRelativePath)
+ ->save();
+ chdir($initialWorkingDir);
+
+ $composerClass = Composer::class;
+ $composer = $this->laravel[$composerClass];
+ if (! ($composer instanceof Composer)) {
+ throw ComposerException::make("$composerClass not registered in your app.");
+ }
+ if (! $composer->updatePackages([$this->modulePackageName], false, $this->output)) {
+ throw ComposerException::make("Failed to update package with composer.");
+ }
}
- protected function getOptions(): array
+ protected function generateComposerJsonFile(): int
{
- return [
-// ['api', 'a', InputOption::VALUE_NONE, 'Generate an api module (with api components, enabled by default).'],
-// ['web', 'w', InputOption::VALUE_NONE, 'Generate a web module (with web components).'],
- ['plain', 'p', InputOption::VALUE_NONE, 'Generate a plain module (without some components).'],
- ['disabled', 'd', InputOption::VALUE_NONE, 'Do not enable the module at creation.'],
- ['force', 'f', InputOption::VALUE_NONE, 'Force the operation to run when the module already exists.'],
- ['entity', null, InputOption::VALUE_REQUIRED, 'Entity name (used to create module components, the default is the name of the module).'],
+ $path = GeneratorHelper::makeModulePath($this->moduleName, 'composer.json');
+ $contents = Stub::create("composer.json.stub", [
+ 'modulePackageName' => $this->modulePackageName,
+ 'moduleName' => $this->moduleName,
+ 'moduleNamespace' => str_replace(
+ '\\',
+ '\\\\',
+ GeneratorHelper::makeModuleNamespace($this->moduleName)
+ ),
+ 'authorName' => config('modules.composer.author.name', 'Example'),
+ 'authorEmail' => config('modules.composer.author.email', 'example@example.com'),
+ ])->render();
+
+ return $this->generate($path, $contents);
+ }
+
+ protected function generateComponents(Module $module): int
+ {
+ $statuses = [$this->generateProviders($module)];
+
+ if ($this->modulePreset !== 'plain') {
+ $statuses[] = $this->generateBaseComponents($module);
+ }
+
+ if ($this->modulePreset === 'api') {
+ $statuses[] = $this->generateApiComponents($module);
+ }
+
+ return $this->isFailure(...$statuses) ? self::FAILURE : self::SUCCESS;
+ }
+
+ protected function generateBaseComponents(Module $module): int
+ {
+ $modulePackageName = $module->getPackageName();
+ $entityName = $this->getEntityName();
+ $snakeEntityName = Str::snake($entityName);
+ $snakePluralEntityName = Str::plural($snakeEntityName);
+
+ return $this->isFailure(
+ $this->call('module:make:factory', [
+ 'name' => "{$entityName}Factory",
+ 'module' => $modulePackageName,
+ '--model' => $entityName,
+ ]),
+ $this->call('module:make:migration', [
+ 'name' => "create_{$snakePluralEntityName}_table",
+ 'module' => $modulePackageName,
+ '--stub' => 'create',
+ ]),
+ $this->call('module:make:seeder', [
+ 'name' => "{$entityName}PermissionsSeeder_1",
+ 'module' => $modulePackageName,
+ '--stub' => 'permissions',
+ '--model' => $entityName,
+ ]),
+ $this->call('module:make:model', [
+ 'name' => $entityName,
+ 'module' => $modulePackageName,
+ '--factory' => "{$entityName}Factory",
+ ]),
+ $this->call('module:make:policy', [
+ 'name' => "{$entityName}Policy",
+ 'module' => $modulePackageName,
+ '--model' => $entityName,
+ ])
+ ) ? self::FAILURE : self::SUCCESS;
+ }
+
+ protected function generateApiComponents(Module $module): int
+ {
+ $actionVerbs = ['create', 'update', 'delete', 'list', 'view'];
+
+ $modulePackageName = $module->getPackageName();
+ $entityName = $this->getEntityName();
+ $pluralEntityName = Str::plural($entityName);
+ $camelEntityName = Str::camel($entityName);
+ $kebabPluralEntityName = Str::kebab($pluralEntityName);
+ $snakePluralEntityName = Str::snake($pluralEntityName);
+
+ $statuses = [
+ $this->call('module:make:query-wizard', [
+ 'name' => "{$pluralEntityName}QueryWizard",
+ 'module' => $modulePackageName,
+ '--stub' => 'eloquent',
+ ]),
+ $this->call('module:make:query-wizard', [
+ 'name' => "{$entityName}QueryWizard",
+ 'module' => $modulePackageName,
+ '--stub' => 'model',
+ ]),
+ $this->call('module:make:resource', [
+ 'name' => "{$entityName}Resource",
+ 'module' => $modulePackageName,
+ '--stub' => 'single',
+ ]),
+ $this->call('module:make:dto', [
+ 'name' => "Create{$entityName}DTO",
+ 'module' => $modulePackageName,
+ ]),
+ $this->call('module:make:dto', [
+ 'name' => "Update{$entityName}DTO",
+ 'module' => $modulePackageName,
+ ]),
];
+
+ foreach ($actionVerbs as $actionVerb) {
+ $studlyActionVerb = Str::studly($actionVerb);
+
+ $resourceClass = "{$entityName}Resource";
+ $dtoClass = "{$studlyActionVerb}{$entityName}DTO";
+ $routeName = 'api.' . $snakePluralEntityName . '.' . $actionVerb;
+
+ if ($actionVerb === "list") {
+ $actionClass = "{$studlyActionVerb}{$pluralEntityName}Action";
+ $requestClass = "{$studlyActionVerb}{$pluralEntityName}Request";
+ $wizardClass = "{$pluralEntityName}QueryWizard";
+ } else {
+ $actionClass = "{$studlyActionVerb}{$entityName}Action";
+ $requestClass = "{$studlyActionVerb}{$entityName}Request";
+ $wizardClass = "{$entityName}QueryWizard";
+ }
+ $statuses[] = $this->call('module:make:action', [
+ 'name' => $actionClass,
+ 'module' => $modulePackageName,
+ '--stub' => $actionVerb,
+ '--dto' => $dtoClass,
+ '--model' => $entityName,
+ '--request' => $requestClass,
+ '--resource' => $resourceClass,
+ '--wizard' => $wizardClass,
+ ]);
+ $statuses[] = $this->call('module:make:request', [
+ 'name' => $requestClass,
+ 'module' => $modulePackageName,
+ '--stub' => $actionVerb,
+ '--ui' => 'api',
+ '--dto' => $dtoClass,
+ '--model' => $entityName,
+ ]);
+
+ $actionMethodsMap = [
+ 'create' => 'post',
+ 'update' => 'patch',
+ 'delete' => 'delete',
+ 'list' => 'get',
+ 'view' => 'get',
+ ];
+
+ $url = $kebabPluralEntityName;
+ if (in_array($actionVerb, ['update', 'delete', 'view'])) {
+ $url .= '/{' . $camelEntityName . '}';
+ }
+
+ $filePath = Str::snake(str_replace('Action', '', $actionClass), '_');
+ $filePath = 'v1/' . $filePath;
+
+ $statuses[] = $this->call('module:make:route', [
+ 'name' => $filePath,
+ 'module' => $modulePackageName,
+ '--ui' => 'api',
+ '--action' => $actionClass,
+ '--method' => $actionMethodsMap[$actionVerb],
+ '--url' => $url,
+ '--name' => $routeName,
+ ]);
+
+ $testClass = $actionVerb === 'list'
+ ? "{$studlyActionVerb}{$pluralEntityName}Test"
+ : "{$studlyActionVerb}{$entityName}Test";
+
+ $statuses[] = $this->call('module:make:test', [
+ 'name' => $testClass,
+ 'module' => $modulePackageName,
+ '--stub' => $actionVerb,
+ '--type' => 'api',
+ '--model' => $entityName,
+ '--route' => $routeName,
+ ]);
+ }
+
+ return $this->isFailure(...$statuses) ? self::FAILURE : self::SUCCESS;
+ }
+
+ protected function generateProviders(Module $module): int
+ {
+ return $this->isFailure(
+ $this->call('module:make:provider', [
+ 'name' => "{$module->getStudlyName()}ServiceProvider",
+ 'module' => $module->getPackageName(),
+ '--stub' => 'module',
+ ]),
+ $this->call('module:make:provider', [
+ 'name' => 'RouteServiceProvider',
+ 'module' => $module->getPackageName(),
+ '--stub' => 'route',
+ ])
+ ) ? self::FAILURE : self::SUCCESS;
}
/**
- * Get module type.
- *
- * @return string
- */
- private function getModuleType(): string
+ * @param int ...$statuses
+ * @return bool
+ */
+ protected function isFailure(...$statuses): bool
{
- if ($this->option('plain')) {
- return 'plain';
+ foreach ($statuses as $status) {
+ if ($status !== self::SUCCESS) {
+ return true;
+ }
}
-// if ($this->option('web')) {
-// return 'web';
-// }
+ return false;
+ }
- return 'api';
+ protected function validateModuleStudlyName(string $name): bool
+ {
+ return preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $name);
+ }
+
+ protected function getEntityName(): string
+ {
+ if ($this->entityName !== null) {
+ return $this->entityName;
+ }
+
+ return $this->entityName = Str::studly($this->getOptionOrAsk(
+ optionName: 'entity',
+ question: 'Enter the entity name (used to create module components)',
+ default: $this->moduleStudlyName
+ ));
+ }
+
+ /**
+ * Not used by ModuleMakeCommand as it fully overrides handle().
+ * Required by abstract base class.
+ */
+ protected function getContents(): string
+ {
+ return '';
}
}
diff --git a/src/Commands/Generators/NotificationMakeCommand.php b/src/Commands/Generators/NotificationMakeCommand.php
index 9d82693..86deaf9 100644
--- a/src/Commands/Generators/NotificationMakeCommand.php
+++ b/src/Commands/Generators/NotificationMakeCommand.php
@@ -2,97 +2,65 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class NotificationMakeCommand extends ComponentGeneratorCommand
+class NotificationMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:notification';
+ protected $signature = 'module:make:notification
+ {name : The name of the notification class}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new notification for the specified module.';
-
- /**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'queued';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
+ protected $description = 'Generate new notification class for the specified module.';
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * The module component type.
*/
- protected string $nameArgument;
+ protected ModuleComponentType $componentType = ModuleComponentType::Notification;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
+ 'name' => 'Enter the notification class name',
];
}
- protected function prepare()
+ protected function getContents(): string
{
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
+ $stub = $this->getOptionOrChoice(
'stub',
'Select the stub you want to use for generator',
['plain', 'queued'],
- 'queued'
+ 'plain'
);
- $this->componentType = 'notification';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
- {
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
- return Stub::create("notification/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("notification/$stub.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/ObserverMakeCommand.php b/src/Commands/Generators/ObserverMakeCommand.php
index a25ab2b..30963ba 100644
--- a/src/Commands/Generators/ObserverMakeCommand.php
+++ b/src/Commands/Generators/ObserverMakeCommand.php
@@ -2,25 +2,26 @@
namespace Laraneat\Modules\Commands\Generators;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Str;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class ObserverMakeCommand extends ComponentGeneratorCommand
+class ObserverMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:observer';
+ protected $signature = 'module:make:observer
+ {name : The name of the observer class}
+ {module? : The name or package name of the app module}
+ {--model= : The class name of the model to be used in the observer}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -30,64 +31,38 @@ class ObserverMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new observer for the specified module.';
/**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
+ * The module component type.
*/
- protected string $componentType = 'observer';
+ protected ModuleComponentType $componentType = ModuleComponentType::Observer;
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $nameArgument;
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['model', null, InputOption::VALUE_REQUIRED, 'The class name of the model to be used in the observer.'],
+ 'name' => 'Enter the observer class name',
];
}
- protected function prepare()
- {
- $this->module = $this->getModule();
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
- $model = $this->getOptionOrAsk(
- 'model',
- 'Enter the class name of the model to be used in the observer',
- '',
- true
+ $modelClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'model',
+ question: 'Enter the class name of the model to be used in the observer',
+ componentType: ModuleComponentType::Model,
+ module: $this->module
);
- $modelClass = $this->getClass($model);
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument),
- 'model' => $modelClass,
- 'modelEntity' => Str::camel($modelClass),
- 'modelNamespace' => $this->getComponentNamespace($this->module, $model, 'model')
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
+ 'model' => class_basename($modelClass),
+ 'modelCamelCase' => Str::camel(class_basename($modelClass)),
+ 'modelNamespace' => $this->getNamespaceOfClass($modelClass),
];
return Stub::create("observer.stub", $stubReplaces)->render();
diff --git a/src/Commands/Generators/PolicyMakeCommand.php b/src/Commands/Generators/PolicyMakeCommand.php
index 91650eb..1ef9a1d 100644
--- a/src/Commands/Generators/PolicyMakeCommand.php
+++ b/src/Commands/Generators/PolicyMakeCommand.php
@@ -2,25 +2,27 @@
namespace Laraneat\Modules\Commands\Generators;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Str;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\GeneratorHelper;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class PolicyMakeCommand extends ComponentGeneratorCommand
+class PolicyMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:policy';
+ protected $signature = 'module:make:policy
+ {name : The name of the policy}
+ {module? : The name or package name of the app module}
+ {--model= : The class name of the model to be used in the policy}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -30,94 +32,56 @@ class PolicyMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new policy for the specified module.';
/**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'full';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
+ * The module component type.
*/
- protected string $nameArgument;
+ protected ModuleComponentType $componentType = ModuleComponentType::Policy;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
- ['model', null, InputOption::VALUE_REQUIRED, 'The class name of the model.'],
+ 'name' => 'Enter the policy class name',
];
}
- protected function prepare()
- {
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
- 'stub',
- 'Select the stub you want to use for generator',
- ['plain', 'full'],
- 'full'
- );
- $this->componentType = 'policy';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
+ $stub = 'plain';
$stubReplaces = [
'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'class' => class_basename($this->nameArgument),
];
- if ($this->stub === 'full') {
- $model = $this->getOptionOrAsk(
- 'model',
- 'Enter the class name of the model',
- '',
- true
+ $modelOption = $this->getOptionOrAsk(
+ 'model',
+ question: 'Enter the class name of the model to be used in the policy (optional)',
+ required: false
+ );
+
+ if ($modelOption) {
+ $modelClass = $this->getFullClass(
+ $modelOption,
+ GeneratorHelper::component(ModuleComponentType::Model)
+ ->getFullNamespace($this->module)
);
- $stubReplaces['model'] = $this->getClass($model);
- $stubReplaces['modelEntity'] = Str::camel($stubReplaces['model']);
- if ($stubReplaces['modelEntity'] === 'user') {
- $stubReplaces['modelEntity'] = 'model';
+ $stub = 'full';
+ $stubReplaces['model'] = class_basename($modelClass);
+ $stubReplaces['modelNamespace'] = $this->getNamespaceOfClass($modelClass);
+ $stubReplaces['modelKebabCase'] = Str::kebab($stubReplaces['model']);
+ $stubReplaces['modelsKebabCase'] = Str::kebab(Str::plural($stubReplaces['model']));
+ $stubReplaces['modelCamelCase'] = Str::camel($stubReplaces['model']);
+ if ($stubReplaces['modelCamelCase'] === 'user') {
+ $stubReplaces['modelCamelCase'] = 'model';
}
- $stubReplaces['modelPermissionEntity'] = Str::snake($stubReplaces['model'], '-');
- $stubReplaces['modelPermissionEntities'] = Str::snake(Str::plural($stubReplaces['model']), '-');
- $stubReplaces['modelNamespace'] = $this->getComponentNamespace($this->module, $model, 'model');
$fullUserClass = $this->getUserModelClass();
-
- $stubReplaces['user'] = $this->getClass($fullUserClass);
+ $stubReplaces['user'] = class_basename($fullUserClass);
$stubReplaces['userNamespace'] = $this->getNamespaceOfClass($fullUserClass);
}
- return Stub::create("policy/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("policy/$stub.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/ProviderMakeCommand.php b/src/Commands/Generators/ProviderMakeCommand.php
index 7ce6044..f2f4fe1 100644
--- a/src/Commands/Generators/ProviderMakeCommand.php
+++ b/src/Commands/Generators/ProviderMakeCommand.php
@@ -2,26 +2,27 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Facades\Modules;
-use Laraneat\Modules\Module;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
use Laraneat\Modules\Support\Generator\GeneratorHelper;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Support\Generator\Stub;
+use Laraneat\Modules\Support\ModuleConfigWriter;
/**
* @group generator
*/
-class ProviderMakeCommand extends ComponentGeneratorCommand
+class ProviderMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:provider';
+ protected $signature = 'module:make:provider
+ {name : The name of the provider class}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -31,96 +32,98 @@ class ProviderMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new provider for the specified module.';
/**
- * The stub name to load for this generator.
- */
- protected string $stub = 'plain';
-
- /**
- * Module instance.
+ * The module component type.
*/
- protected Module $module;
+ protected ModuleComponentType $componentType = ModuleComponentType::Provider;
/**
- * Component type.
+ * Selected stub name (cached for afterGenerate).
*/
- protected string $componentType;
+ protected string $selectedStub;
/**
- * Prepared 'name' argument.
+ * Stub replacements (cached for afterGenerate).
*/
- protected string $nameArgument;
+ protected array $stubReplaces;
/**
- * Get the console command options.
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
+ 'name' => 'Enter the provider class name',
];
}
- protected function prepare(): void
+ protected function getContents(): string
{
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
+ $this->selectedStub = $this->getOptionOrChoice(
'stub',
'Select the stub you want to use for generator',
- ['plain', 'module', 'route', 'event'],
+ ['plain', 'module', 'event', 'route'],
'plain'
);
- $this->componentType = 'provider';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
- protected function getTemplateContents(): string
- {
- $stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ $this->stubReplaces = [
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
- if ($this->stub === 'module') {
- $stubReplaces = array_merge($stubReplaces, [
- 'moduleName' => $this->module->getStudlyName(),
- 'moduleKey' => $this->module->getKey(),
- 'commandsPath' => GeneratorHelper::component('cli-command')->getPath(),
- 'langPath' => GeneratorHelper::component('lang')->getPath(),
- 'configPath' => GeneratorHelper::component('config')->getPath(),
- 'viewsPath' => GeneratorHelper::component('view')->getPath(),
- 'migrationsPath' => GeneratorHelper::component('migration')->getPath(),
+ $providerDir = GeneratorHelper::component(ModuleComponentType::Provider)->getFullPath($this->module);
+
+ if ($this->selectedStub === 'module') {
+ $this->stubReplaces = array_merge($this->stubReplaces, [
+ 'modulePackageName' => $this->module->getPackageName(),
+ 'moduleNameKebabCase' => $this->module->getKebabName(),
+ 'commandsNamespace' => str_replace('\\', '\\\\', GeneratorHelper::component(ModuleComponentType::CliCommand)->getFullNamespace($this->module)),
+ 'commandsPath' => GeneratorHelper::makeRelativePath(
+ $providerDir,
+ GeneratorHelper::component(ModuleComponentType::CliCommand)->getFullPath($this->module)
+ ),
+ 'configPath' => GeneratorHelper::makeRelativePath(
+ $providerDir,
+ GeneratorHelper::component(ModuleComponentType::Config)->getFullPath($this->module)
+ ),
+ 'langPath' => GeneratorHelper::makeRelativePath(
+ $providerDir,
+ GeneratorHelper::component(ModuleComponentType::Lang)->getFullPath($this->module)
+ ),
+ 'viewsPath' => GeneratorHelper::makeRelativePath(
+ $providerDir,
+ GeneratorHelper::component(ModuleComponentType::View)->getFullPath($this->module)
+ ),
+ 'migrationsPath' => GeneratorHelper::makeRelativePath(
+ $providerDir,
+ GeneratorHelper::component(ModuleComponentType::Migration)->getFullPath($this->module)
+ ),
]);
- } elseif ($this->stub === 'route') {
- $stubReplaces = array_merge($stubReplaces, [
- 'moduleName' => $this->module->getStudlyName(),
- 'webControllerNamespace' => str_replace('\\', '\\\\', GeneratorHelper::component('web-controller')->getFullNamespace($this->module)),
- 'apiControllerNamespace' => str_replace('\\', '\\\\', GeneratorHelper::component('api-controller')->getFullNamespace($this->module)),
- 'webRoutesPath' => GeneratorHelper::component('web-route')->getPath(),
- 'apiRoutesPath' => GeneratorHelper::component('api-route')->getPath()
+ } elseif ($this->selectedStub === 'route') {
+ $this->stubReplaces = array_merge($this->stubReplaces, [
+ 'modulePackageName' => $this->module->getPackageName(),
+ 'webControllerNamespace' => str_replace('\\', '\\\\', GeneratorHelper::component(ModuleComponentType::WebController)->getFullNamespace($this->module)),
+ 'apiControllerNamespace' => str_replace('\\', '\\\\', GeneratorHelper::component(ModuleComponentType::ApiController)->getFullNamespace($this->module)),
+ 'webRoutesPath' => GeneratorHelper::makeRelativePath(
+ $providerDir,
+ GeneratorHelper::component(ModuleComponentType::WebRoute)->getFullPath($this->module)
+ ),
+ 'apiRoutesPath' => GeneratorHelper::makeRelativePath(
+ $providerDir,
+ GeneratorHelper::component(ModuleComponentType::ApiRoute)->getFullPath($this->module)
+ ),
]);
}
- $this->addProviderClassToModuleJson($stubReplaces['namespace'] . '\\' . $stubReplaces['class']);
-
- return Stub::create("provider/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("provider/{$this->selectedStub}.stub", $this->stubReplaces)->render();
}
- protected function addProviderClassToModuleJson(string $providerClass): void
+ protected function afterGenerate(): void
{
- $json = $this->module->json();
- $providers = $json->get('providers');
- if (! is_array($providers)) {
- $providers = [];
- }
- $providers[] = $providerClass;
- $json->set('providers', $providers)
- ->save();
-
- Modules::flushCache();
+ $this->laravel->make(ModuleConfigWriter::class)
+ ->addProvider($this->module, $this->stubReplaces['namespace'] . '\\' . $this->stubReplaces['class']);
}
}
diff --git a/src/Commands/Generators/QueryWizardMakeCommand.php b/src/Commands/Generators/QueryWizardMakeCommand.php
index 98dd9d9..79dac50 100644
--- a/src/Commands/Generators/QueryWizardMakeCommand.php
+++ b/src/Commands/Generators/QueryWizardMakeCommand.php
@@ -2,97 +2,71 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class QueryWizardMakeCommand extends ComponentGeneratorCommand
+class QueryWizardMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:wizard';
+ protected $signature = 'module:make:query-wizard
+ {name : The name of the query-wizard class}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new query-wizard for the specified module.';
-
- /**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'eloquent';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
+ protected $description = 'Generate new query-wizard class for the specified module.';
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * The module component type.
*/
- protected string $nameArgument;
+ protected ModuleComponentType $componentType = ModuleComponentType::ApiQueryWizard;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
+ 'name' => 'Enter the query-wizard class name',
];
}
- protected function prepare()
+ protected function beforeGenerate(): void
{
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
+ $this->ensurePackageIsInstalledOrWarn('jackardios/laravel-query-wizard');
+ }
+
+ protected function getContents(): string
+ {
+ $stub = $this->getOptionOrChoice(
'stub',
'Select the stub you want to use for generator',
- ['eloquent', 'model', 'scout', 'elastic'],
+ ['eloquent', 'model'],
'eloquent'
);
- $this->componentType = 'api-query-wizard';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
- protected function getTemplateContents(): string
- {
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
- return Stub::create("query-wizard/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("query-wizard/$stub.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/RequestMakeCommand.php b/src/Commands/Generators/RequestMakeCommand.php
index d35a5eb..88c6f54 100644
--- a/src/Commands/Generators/RequestMakeCommand.php
+++ b/src/Commands/Generators/RequestMakeCommand.php
@@ -2,25 +2,29 @@
namespace Laraneat\Modules\Commands\Generators;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Str;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class RequestMakeCommand extends ComponentGeneratorCommand
+class RequestMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:request';
+ protected $signature = 'module:make:request
+ {name : The name of the request}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--ui= : The UI for which the request will be created}
+ {--dto= : The class name of the DTO to be used in the request}
+ {--model= : The class name of the model to be used in the request}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -31,111 +35,75 @@ class RequestMakeCommand extends ComponentGeneratorCommand
/**
* The UI for which the request will be created.
- *
- * @var string
- */
- protected string $ui = 'api';
-
- /**
- * The stub name to load for this generator
- *
- * @var string
- */
- protected string $stub = 'plain';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
+ * ('web' or 'api')
*/
- protected string $nameArgument;
+ protected string $ui;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['ui', null, InputOption::VALUE_REQUIRED, 'The UI for which the request will be created.'],
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
- ['dto', null, InputOption::VALUE_REQUIRED, 'The class name of the DTO to be used in the request.'],
- ['model', null, InputOption::VALUE_REQUIRED, 'The class name of the model to be used in the request.'],
+ 'name' => 'Enter the request class name',
];
}
- protected function prepare()
+ protected function beforeGenerate(): void
{
- $this->module = $this->getModule();
$this->ui = $this->getOptionOrChoice(
'ui',
- 'Select the UI for which the request will be created',
- ['api', 'web'],
- 'api'
+ question: 'Enter the UI for which the request will be created',
+ choices: ['api', 'web'],
+ default: 'api'
);
- $stubChoices = ($this->ui === "web")
- ? ['plain', 'create', 'delete', 'update']
- : ['plain', 'create', 'delete', 'list', 'update', 'view'];
- $this->stub = $this->getOptionOrChoice(
- 'stub',
- 'Select the stub you want to use for generator',
- $stubChoices,
- 'plain'
- );
- $this->componentType = "{$this->ui}-request";
- $this->nameArgument = $this->getTrimmedArgument('name');
+ $this->componentType = $this->ui === 'api'
+ ? ModuleComponentType::ApiRequest
+ : ModuleComponentType::WebRequest;
}
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
+ $stub = $this->getOptionOrChoice(
+ optionName: 'stub',
+ question: 'Select the stub you want to use for generator',
+ choices: ($this->ui === "web")
+ ? ['plain', 'create', 'delete', 'update']
+ : ['plain', 'create', 'delete', 'list', 'update', 'view'],
+ default: 'plain'
+ );
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
- if ($this->stub !== 'plain') {
- if ($this->stub === 'create' || $this->stub === 'update') {
- $dto = $this->getOptionOrAsk(
- 'dto',
- 'Enter the class name of the DTO to be used in the request',
- '',
- true
+ if ($stub !== 'plain') {
+ if ($stub === 'create' || $stub === 'update') {
+ $dtoClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'dto',
+ question: 'Enter the class name of the DTO to be used in the request',
+ componentType: ModuleComponentType::Dto,
+ module: $this->module
);
- $stubReplaces['dto'] = $this->getClass($dto);
- $stubReplaces['dtoNamespace'] = $this->getComponentNamespace($this->module, $dto, 'dto');
+ $stubReplaces['dto'] = class_basename($dtoClass);
+ $stubReplaces['dtoNamespace'] = $this->getNamespaceOfClass($dtoClass);
}
- $model = $this->getOptionOrAsk(
- 'model',
- 'Enter the class name of the model to be used in the request',
- '',
- true
+ $modelClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'model',
+ question: 'Enter the class name of the model to be used in the request',
+ componentType: ModuleComponentType::Model,
+ module: $this->module
);
- $stubReplaces['model'] = $this->getClass($model);
- $stubReplaces['modelEntity'] = Str::camel($stubReplaces['model']);
- $stubReplaces['modelNamespace'] = $this->getComponentNamespace($this->module, $model, 'model');
+ $stubReplaces['model'] = class_basename($modelClass);
+ $stubReplaces['modelCamelCase'] = Str::camel($stubReplaces['model']);
+ $stubReplaces['modelNamespace'] = $this->getNamespaceOfClass($modelClass);
}
- return Stub::create("request/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("request/$stub.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/ResourceMakeCommand.php b/src/Commands/Generators/ResourceMakeCommand.php
index dd0f0a9..7abae6d 100644
--- a/src/Commands/Generators/ResourceMakeCommand.php
+++ b/src/Commands/Generators/ResourceMakeCommand.php
@@ -2,97 +2,66 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class ResourceMakeCommand extends ComponentGeneratorCommand
+class ResourceMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:resource';
+ protected $signature = 'module:make:resource
+ {name : The name of the resource class}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new API resource for the specified module.';
-
- /**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'single';
+ protected $description = 'Generate new resource class for the specified module.';
/**
- * Module instance.
- *
- * @var Module
+ * The module component type.
*/
- protected Module $module;
+ protected ModuleComponentType $componentType = ModuleComponentType::ApiResource;
/**
- * Component type.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $componentType;
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
- */
- protected string $nameArgument;
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
+ 'name' => 'Enter the resource class name',
];
}
- protected function prepare()
+ protected function getContents(): string
{
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
+ $stub = $this->getOptionOrChoice(
'stub',
'Select the stub you want to use for generator',
['single', 'collection'],
- 'single'
+ 'eloquent'
);
- $this->componentType = 'api-resource';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
- {
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
- return Stub::create("resource/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("resource/$stub.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/RouteMakeCommand.php b/src/Commands/Generators/RouteMakeCommand.php
index 2865345..e34618d 100644
--- a/src/Commands/Generators/RouteMakeCommand.php
+++ b/src/Commands/Generators/RouteMakeCommand.php
@@ -2,25 +2,30 @@
namespace Laraneat\Modules\Commands\Generators;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Str;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class RouteMakeCommand extends ComponentGeneratorCommand
+class RouteMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:route';
+ protected $signature = 'module:make:route
+ {name : The name of the route}
+ {module? : The name or package name of the app module}
+ {--ui= : The UI for which the route will be created}
+ {--action= : The class name of the action to be used in the route}
+ {--method= : HTTP request method}
+ {--url= : Route URL}
+ {--name= : Route name}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -30,74 +35,39 @@ class RouteMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new route for the specified module.';
/**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
-
- /**
- * The UI for which the request will be created.
- *
- * @var string
- */
- protected string $ui = 'api';
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
+ * The UI for which the route will be created.
+ * ('web' or 'api')
*/
- protected string $nameArgument;
+ protected string $ui;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['ui', null, InputOption::VALUE_REQUIRED, 'The UI for which the route will be created.'],
- ['action', null, InputOption::VALUE_REQUIRED, 'The class name of the action to be used in the route.'],
- ['method', 'm', InputOption::VALUE_REQUIRED, 'HTTP request method.'],
- ['url', 'u', InputOption::VALUE_REQUIRED, 'Route URL.'],
- ['name', null, InputOption::VALUE_REQUIRED, 'Route name.'],
+ 'name' => 'Enter the route class name',
];
}
- protected function prepare()
+ protected function beforeGenerate(): void
{
- $this->module = $this->getModule();
$this->ui = $this->getOptionOrChoice(
'ui',
- 'Select the UI for which the request will be created',
- ['api', 'web'],
- 'api'
+ question: 'Enter the UI for which the route will be created',
+ choices: ['api', 'web'],
+ default: 'api'
);
- $this->componentType = "{$this->ui}-route";
- $this->nameArgument = $this->getTrimmedArgument('name');
+ $this->componentType = $this->ui === 'api'
+ ? ModuleComponentType::ApiRoute
+ : ModuleComponentType::WebRoute;
}
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
$url = $this->getOptionOrAsk(
'url',
'Enter the route URL',
- '',
- true
);
$method = $this->getOptionOrChoice(
'method',
@@ -105,25 +75,24 @@ protected function getTemplateContents(): string
['get', 'post', 'put', 'patch', 'delete', 'options'],
'get'
);
- $action = $this->getOptionOrAsk(
- 'action',
- 'Enter the class name of the action to be used in the route',
- $this->generateDefaultActionName($url, $method),
- true
- );
$name = $this->getOptionOrAsk(
'name',
'Enter the route name',
$this->generateDefaultRouteName($url, $method),
- true
+ );
+ $actionClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'action',
+ question: 'Enter the class name of the action to be used in the route',
+ componentType: ModuleComponentType::Action,
+ module: $this->module
);
$stubReplaces = [
- 'actionNamespace' => $this->getComponentNamespace($this->module, $action, 'action'),
- 'action' => $this->getClass($action),
'method' => $method,
'url' => $url,
'name' => $name,
];
+ $stubReplaces['action'] = class_basename($actionClass);
+ $stubReplaces['actionNamespace'] = $this->getNamespaceOfClass($actionClass);
return Stub::create("route.stub", $stubReplaces)->render();
}
@@ -151,6 +120,7 @@ protected function generateDefaultRouteName(string $url, string $method): string
{
$verb = $this->recognizeActionVerbByMethod($url, $method);
$resource = Str::snake($this->recognizeResourceByUrl($url));
+
return Str::lower($this->ui) . '.' . $resource . '.' . $verb;
}
diff --git a/src/Commands/Generators/RuleMakeCommand.php b/src/Commands/Generators/RuleMakeCommand.php
index de35145..2853588 100644
--- a/src/Commands/Generators/RuleMakeCommand.php
+++ b/src/Commands/Generators/RuleMakeCommand.php
@@ -2,68 +2,56 @@
namespace Laraneat\Modules\Commands\Generators;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class RuleMakeCommand extends ComponentGeneratorCommand
+class RuleMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:rule';
+ protected $signature = 'module:make:rule
+ {name : The name of the rule class}
+ {module? : The name or package name of the app module}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Generate new rule for the specified module.';
+ protected $description = 'Generate new rule class for the specified module.';
/**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
+ * The module component type.
*/
- protected string $componentType = 'rule';
+ protected ModuleComponentType $componentType = ModuleComponentType::Rule;
/**
- * Prepared 'name' argument.
- *
- * @var string
+ * Prompt for missing input arguments using the returned questions.
*/
- protected string $nameArgument;
-
- protected function prepare()
+ protected function promptForMissingArgumentsUsing(): array
{
- $this->module = $this->getModule();
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
+ return [
+ 'name' => 'Enter the rule class name',
+ ];
}
- protected function getTemplateContents(): string
+ protected function getContents(): string
{
$stubReplaces = [
- 'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument),
+ 'namespace' => $this->getComponentNamespace(
+ $this->module,
+ $this->nameArgument,
+ $this->componentType
+ ),
+ 'class' => class_basename($this->nameArgument),
];
return Stub::create("rule.stub", $stubReplaces)->render();
diff --git a/src/Commands/Generators/SeederMakeCommand.php b/src/Commands/Generators/SeederMakeCommand.php
index bda2cd0..32a538f 100644
--- a/src/Commands/Generators/SeederMakeCommand.php
+++ b/src/Commands/Generators/SeederMakeCommand.php
@@ -2,25 +2,27 @@
namespace Laraneat\Modules\Commands\Generators;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Str;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class SeederMakeCommand extends ComponentGeneratorCommand
+class SeederMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:seeder';
+ protected $signature = 'module:make:seeder
+ {name : The name of the seeder}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--model= : The class name of the model to be used in the seeder}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -30,92 +32,53 @@ class SeederMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new seeder for the specified module.';
/**
- * The stub name to load for this generator.
- *
- * @var string
- */
- protected string $stub = 'plain';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
+ * The module component type.
*/
- protected string $nameArgument;
+ protected ModuleComponentType $componentType = ModuleComponentType::Seeder;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
- ['model', null, InputOption::VALUE_REQUIRED, 'The class name of the model to be used in the seeder.'],
+ 'name' => 'Enter the seeder class name',
];
}
- protected function prepare()
+ protected function getContents(): string
{
- $this->module = $this->getModule();
- $this->stub = $this->getOptionOrChoice(
+ $stub = $this->getOptionOrChoice(
'stub',
'Select the stub you want to use for generator',
['plain', 'permissions'],
'plain'
);
- $this->componentType = 'seeder';
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
-
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
- {
$stubReplaces = [
'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'class' => class_basename($this->nameArgument),
];
- if ($this->stub === 'permissions') {
- $createPermissionAction = $this->getCreatePermissionActionClass();
- $stubReplaces['createPermissionAction'] = $this->getClass($createPermissionAction);
- $stubReplaces['actionNamespace'] = $this->getNamespaceOfClass($createPermissionAction);
+ if ($stub === 'permissions') {
+ $createPermissionActionClass = $this->getCreatePermissionActionClass();
+ $stubReplaces['createPermissionAction'] = class_basename($createPermissionActionClass);
+ $stubReplaces['createPermissionActionNamespace'] = $this->getNamespaceOfClass($createPermissionActionClass);
- $createPermissionDTO = $this->getCreatePermissionDTOClass();
- $stubReplaces['createPermissionDTO'] = $this->getClass($createPermissionDTO);
- $stubReplaces['dtoNamespace'] = $this->getNamespaceOfClass($createPermissionDTO);
+ $createPermissionDTOClass = $this->getCreatePermissionDTOClass();
+ $stubReplaces['createPermissionDTO'] = class_basename($createPermissionDTOClass);
+ $stubReplaces['createPermissionDTONamespace'] = $this->getNamespaceOfClass($createPermissionDTOClass);
- $model = $this->getOptionOrAsk(
- 'model',
- 'Enter the class name of the model to be used in the seeder',
- '',
- true
+ $modelClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'model',
+ question: 'Enter the class name of the model to be used in the seeder',
+ componentType: ModuleComponentType::Model,
+ module: $this->module
);
- $modelClass = $this->getClass($model);
- $stubReplaces['modelPermissionEntity'] = Str::snake($modelClass, '-');
- $stubReplaces['modelPermissionEntities'] = Str::plural($stubReplaces['modelPermissionEntity']);
+ $stubReplaces['modelKebabCase'] = Str::kebab(class_basename($modelClass));
+ $stubReplaces['modelsKebabCase'] = Str::plural($stubReplaces['modelKebabCase']);
}
- return Stub::create("seeder/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("seeder/$stub.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/TestMakeCommand.php b/src/Commands/Generators/TestMakeCommand.php
index 7617bb9..37395e3 100644
--- a/src/Commands/Generators/TestMakeCommand.php
+++ b/src/Commands/Generators/TestMakeCommand.php
@@ -2,25 +2,29 @@
namespace Laraneat\Modules\Commands\Generators;
+use Illuminate\Contracts\Console\PromptsForMissingInput;
use Illuminate\Support\Str;
-use Laraneat\Modules\Module;
-use Laraneat\Modules\Support\Stub;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputOption;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Support\Generator\Stub;
/**
* @group generator
*/
-class TestMakeCommand extends ComponentGeneratorCommand
+class TestMakeCommand extends BaseComponentGeneratorCommand implements PromptsForMissingInput
{
- use ModuleCommandTrait;
-
/**
* The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:make:test';
+ protected $signature = 'module:make:test
+ {name : The name of the test}
+ {module? : The name or package name of the app module}
+ {--s|stub= : The stub name to load for this generator}
+ {--type : The type of test to be created}
+ {--model= : The class name of the model to be used in the test}
+ {--route= : The route name for HTTP tests}
+ {--force : Overwrite the file if it already exists}';
/**
* The console command description.
@@ -30,127 +34,88 @@ class TestMakeCommand extends ComponentGeneratorCommand
protected $description = 'Generate new test for the specified module.';
/**
- * The type of test to be created.
- *
- * @var string
- */
- protected string $type = 'unit';
-
- /**
- * The stub name to load for this generator
- *
- * @var string
- */
- protected string $stub = 'plain';
-
- /**
- * Module instance.
- *
- * @var Module
- */
- protected Module $module;
-
- /**
- * Component type.
- *
- * @var string
- */
- protected string $componentType;
-
- /**
- * Prepared 'name' argument.
- *
- * @var string
+ * The test type.
*/
- protected string $nameArgument;
+ protected string $type;
/**
- * Get the console command options.
- *
- * @return array
+ * Prompt for missing input arguments using the returned questions.
*/
- protected function getOptions(): array
+ protected function promptForMissingArgumentsUsing(): array
{
return [
- ['type', 't', InputOption::VALUE_REQUIRED, 'The type of test to be created.'],
- ['stub', 's', InputOption::VALUE_REQUIRED, 'The stub name to load for this generator.'],
- ['model', null, InputOption::VALUE_REQUIRED, 'The class name of the model to be used in the test.'],
- ['route', null, InputOption::VALUE_REQUIRED, 'The route name for HTTP tests.'],
+ 'name' => 'Enter the test class name',
];
}
- protected function prepare()
+ protected function beforeGenerate(): void
{
- $this->module = $this->getModule();
$this->type = $this->getOptionOrChoice(
'type',
- 'Select the type of test to be created',
- ['unit', 'feature', 'api', 'web', 'cli'],
- 'unit'
+ question: 'Enter the type of test to be created',
+ choices: ['unit', 'feature', 'api', 'web', 'cli'],
+ default: 'unit'
);
+ $this->componentType = match($this->type) {
+ 'unit' => ModuleComponentType::UnitTest,
+ 'feature' => ModuleComponentType::FeatureTest,
+ 'api' => ModuleComponentType::ApiTest,
+ 'web' => ModuleComponentType::WebTest,
+ 'cli' => ModuleComponentType::CliTest,
+ default => ModuleComponentType::UnitTest,
+ };
+ }
- $stubsMap = [
+ protected function getContents(): string
+ {
+ $stubChoices = match($this->type) {
+ 'unit' => ['plain'],
+ 'feature' => ['plain'],
'api' => ['plain', 'create', 'delete', 'list', 'update', 'view'],
'web' => ['plain', 'create', 'delete', 'update'],
'cli' => ['plain'],
- 'unit' => ['plain'],
- 'feature' => ['plain']
- ];
- $stubChoices = $stubsMap[$this->type];
- if (count($stubChoices) === 1) {
- $this->stub = $stubChoices[0];
- } else {
- $this->stub = $this->getOptionOrChoice(
+ default => ['plain'],
+ };
+
+ $stub = count($stubChoices) === 1
+ ? $stubChoices[0]
+ : $this->getOptionOrChoice(
'stub',
'Select the stub you want to use for generator',
$stubChoices,
'plain'
);
- }
-
- $this->componentType = "{$this->type}-test";
- $this->nameArgument = $this->getTrimmedArgument('name');
- }
- protected function getDestinationFilePath(): string
- {
- return $this->getComponentPath($this->module, $this->nameArgument, $this->componentType);
- }
-
- protected function getTemplateContents(): string
- {
$stubReplaces = [
- 'moduleKey' => $this->module->getKey(),
+ 'group' => $this->module->getKebabName(),
'namespace' => $this->getComponentNamespace($this->module, $this->nameArgument, $this->componentType),
- 'class' => $this->getClass($this->nameArgument)
+ 'class' => class_basename($this->nameArgument),
];
- if ($this->stub !== 'plain') {
- $model = $this->getOptionOrAsk(
- 'model',
- 'Enter the class name of the model to be used in the test',
- '',
- true
+ if ($stub !== 'plain') {
+ $modelClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'model',
+ question: 'Enter the class name of the model to be used in the test',
+ componentType: ModuleComponentType::Model,
+ module: $this->module
);
- $stubReplaces['model'] = $this->getClass($model);
- $stubReplaces['modelSnake'] = Str::snake($stubReplaces['model']);
+ $stubReplaces['model'] = class_basename($modelClass);
+ $stubReplaces['modelNamespace'] = $this->getNamespaceOfClass($modelClass);
$stubReplaces['models'] = Str::plural($stubReplaces['model']);
- $stubReplaces['modelsSnake'] = Str::snake($stubReplaces['models']);
- $stubReplaces['modelEntity'] = Str::camel($stubReplaces['model']);
- $stubReplaces['modelNamespace'] = $this->getComponentNamespace($this->module, $model, 'model');
- $stubReplaces['modelPermissionEntity'] = Str::snake($stubReplaces['model'], '-');
- $stubReplaces['modelPermissionEntities'] = Str::plural($stubReplaces['modelPermissionEntity']);
+ $stubReplaces['modelCamelCase'] = Str::camel($stubReplaces['model']);
+ $stubReplaces['modelSnakeCase'] = Str::snake($stubReplaces['model']);
+ $stubReplaces['modelsSnakeCase'] = Str::snake($stubReplaces['models']);
+ $stubReplaces['modelKebabCase'] = Str::kebab($stubReplaces['model']);
+ $stubReplaces['modelsKebabCase'] = Str::plural($stubReplaces['modelKebabCase']);
}
if (in_array($this->type, ['api', 'web'])) {
$stubReplaces['routeName'] = $this->getOptionOrAsk(
'route',
- 'Enter the route name for HTTP tests',
- '',
- true
+ 'Enter the route name for HTTP tests'
);
}
- return Stub::create("test/{$this->type}/{$this->stub}.stub", $stubReplaces)->render();
+ return Stub::create("test/{$this->type}/{$stub}.stub", $stubReplaces)->render();
}
}
diff --git a/src/Commands/Generators/stubs/action/create.stub b/src/Commands/Generators/stubs/action/create.stub
index 8969a80..1340d64 100644
--- a/src/Commands/Generators/stubs/action/create.stub
+++ b/src/Commands/Generators/stubs/action/create.stub
@@ -2,15 +2,17 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Actions\Action;
-use Illuminate\Http\JsonResponse;
use {{ dtoNamespace }}\{{ dto }};
use {{ modelNamespace }}\{{ model }};
use {{ requestNamespace }}\{{ request }};
use {{ resourceNamespace }}\{{ resource }};
+use Illuminate\Http\JsonResponse;
+use Lorisleiva\Actions\Concerns\AsAction;
-class {{ class }} extends Action
+class {{ class }}
{
+ use AsAction;
+
public function handle({{ dto }} $dto): {{ model }}
{
return {{ model }}::create($dto->all());
@@ -18,8 +20,8 @@ class {{ class }} extends Action
public function asController({{ request }} $request): JsonResponse
{
- ${{ modelEntity }} = $this->handle($request->toDTO());
+ ${{ modelCamelCase }} = $this->handle($request->toDTO());
- return (new {{ resource }}(${{ modelEntity }}))->created();
+ return (new {{ resource }}(${{ modelCamelCase }}))->created();
}
}
diff --git a/src/Commands/Generators/stubs/action/delete.stub b/src/Commands/Generators/stubs/action/delete.stub
index b0b3784..b210dcc 100644
--- a/src/Commands/Generators/stubs/action/delete.stub
+++ b/src/Commands/Generators/stubs/action/delete.stub
@@ -2,21 +2,23 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Actions\Action;
-use Illuminate\Http\JsonResponse;
use {{ modelNamespace }}\{{ model }};
use {{ requestNamespace }}\{{ request }};
+use Lorisleiva\Actions\Concerns\AsAction;
+use Symfony\Component\HttpFoundation\Response;
-class {{ class }} extends Action
+class {{ class }}
{
- public function handle({{ model }} ${{ modelEntity }}): bool
+ use AsAction;
+
+ public function handle({{ model }} ${{ modelCamelCase }}): bool
{
- return ${{ modelEntity }}->delete();
+ return ${{ modelCamelCase }}->delete();
}
- public function asController({{ request }} $request, {{ model }} ${{ modelEntity }}): JsonResponse
+ public function asController({{ request }} $request, {{ model }} ${{ modelCamelCase }}): Response
{
- $this->handle(${{ modelEntity }});
+ $this->handle(${{ modelCamelCase }});
return $this->noContent();
}
diff --git a/src/Commands/Generators/stubs/action/list.stub b/src/Commands/Generators/stubs/action/list.stub
index 9f6fa04..011b4b2 100644
--- a/src/Commands/Generators/stubs/action/list.stub
+++ b/src/Commands/Generators/stubs/action/list.stub
@@ -2,24 +2,26 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Actions\Action;
-use Illuminate\Pagination\AbstractPaginator;
-use Illuminate\Http\Resources\Json\ResourceCollection;
use {{ modelNamespace }}\{{ model }};
use {{ queryWizardNamespace }}\{{ queryWizard }};
use {{ requestNamespace }}\{{ request }};
use {{ resourceNamespace }}\{{ resource }};
+use Illuminate\Contracts\Pagination\LengthAwarePaginator;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use Lorisleiva\Actions\Concerns\AsAction;
-class {{ class }} extends Action
+class {{ class }}
{
- public function handle({{ request }} $request): AbstractPaginator
+ use AsAction;
+
+ public function handle({{ request }} $request): LengthAwarePaginator
{
return {{ queryWizard }}::for({{ model }}::query())
->build()
- ->jsonPaginate();
+ ->paginate();
}
- public function asController({{ request }} $request): ResourceCollection
+ public function asController({{ request }} $request): AnonymousResourceCollection
{
return {{ resource }}::collection($this->handle($request));
}
diff --git a/src/Commands/Generators/stubs/action/plain.stub b/src/Commands/Generators/stubs/action/plain.stub
index b9abacf..32d49ea 100644
--- a/src/Commands/Generators/stubs/action/plain.stub
+++ b/src/Commands/Generators/stubs/action/plain.stub
@@ -2,10 +2,12 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Actions\Action;
+use Lorisleiva\Actions\Concerns\AsAction;
-class {{ class }} extends Action
+class {{ class }}
{
+ use AsAction;
+
public function handle()
{
//
diff --git a/src/Commands/Generators/stubs/action/update.stub b/src/Commands/Generators/stubs/action/update.stub
index 38d8446..a97f569 100644
--- a/src/Commands/Generators/stubs/action/update.stub
+++ b/src/Commands/Generators/stubs/action/update.stub
@@ -2,32 +2,31 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Actions\Action;
-use App\Ship\Exceptions\UpdateResourceFailedException;
use {{ dtoNamespace }}\{{ dto }};
use {{ modelNamespace }}\{{ model }};
use {{ requestNamespace }}\{{ request }};
use {{ resourceNamespace }}\{{ resource }};
+use Lorisleiva\Actions\Concerns\AsAction;
-class {{ class }} extends Action
+class {{ class }}
{
- public function handle({{ model }} ${{ modelEntity }}, {{ dto }} $dto): {{ model }}
+ use AsAction;
+
+ public function handle({{ model }} ${{ modelCamelCase }}, {{ dto }} $dto): {{ model }}
{
$data = $dto->all();
- if (empty($data)) {
- throw new UpdateResourceFailedException();
+ if ($data) {
+ ${{ modelCamelCase }}->update($data);
}
- ${{ modelEntity }}->update($data);
-
- return ${{ modelEntity }};
+ return ${{ modelCamelCase }};
}
- public function asController({{ request }} $request, {{ model }} ${{ modelEntity }}): {{ resource }}
+ public function asController({{ request }} $request, {{ model }} ${{ modelCamelCase }}): {{ resource }}
{
- ${{ modelEntity }} = $this->handle(${{ modelEntity }}, $request->toDTO());
+ ${{ modelCamelCase }} = $this->handle(${{ modelCamelCase }}, $request->toDTO());
- return new {{ resource }}(${{ modelEntity }});
+ return new {{ resource }}(${{ modelCamelCase }});
}
}
diff --git a/src/Commands/Generators/stubs/action/view.stub b/src/Commands/Generators/stubs/action/view.stub
index d02f0ad..7b16531 100644
--- a/src/Commands/Generators/stubs/action/view.stub
+++ b/src/Commands/Generators/stubs/action/view.stub
@@ -2,22 +2,24 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Actions\Action;
-use Illuminate\Database\Eloquent\Model;
use {{ modelNamespace }}\{{ model }};
use {{ queryWizardNamespace }}\{{ queryWizard }};
use {{ requestNamespace }}\{{ request }};
use {{ resourceNamespace }}\{{ resource }};
+use Illuminate\Database\Eloquent\Model;
+use Lorisleiva\Actions\Concerns\AsAction;
-class {{ class }} extends Action
+class {{ class }}
{
- public function handle({{ request }} $request, {{ model }} ${{ modelEntity }}): Model
+ use AsAction;
+
+ public function handle({{ request }} $request, {{ model }} ${{ modelCamelCase }}): Model
{
- return {{ queryWizard }}::for(${{ modelEntity }})->build();
+ return {{ queryWizard }}::for(${{ modelCamelCase }})->build();
}
- public function asController({{ request }} $request, {{ model }} ${{ modelEntity }}): {{ resource }}
+ public function asController({{ request }} $request, {{ model }} ${{ modelCamelCase }}): {{ resource }}
{
- return new {{ resource }}($this->handle($request, ${{ modelEntity }}));
+ return new {{ resource }}($this->handle($request, ${{ modelCamelCase }}));
}
}
diff --git a/src/Commands/Generators/stubs/command.stub b/src/Commands/Generators/stubs/command.stub
index cbe9c7c..8adfa16 100755
--- a/src/Commands/Generators/stubs/command.stub
+++ b/src/Commands/Generators/stubs/command.stub
@@ -2,9 +2,7 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Console\Command;
-use Symfony\Component\Console\Input\InputOption;
-use Symfony\Component\Console\Input\InputArgument;
+use Illuminate\Console\Command;
class {{ class }} extends Command
{
@@ -13,14 +11,14 @@ class {{ class }} extends Command
*
* @var string
*/
- protected $name = '{{ command }}';
+ protected $signature = '{{ signature }}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Command description.';
+ protected $description = '{{ description }}';
/**
* Execute the console command.
@@ -29,24 +27,4 @@ class {{ class }} extends Command
{
return self::SUCCESS;
}
-
- /**
- * 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],
- ];
- }
}
diff --git a/src/Commands/Generators/stubs/composer.json.stub b/src/Commands/Generators/stubs/composer.json.stub
old mode 100755
new mode 100644
index 948782b..4c24087
--- a/src/Commands/Generators/stubs/composer.json.stub
+++ b/src/Commands/Generators/stubs/composer.json.stub
@@ -1,6 +1,7 @@
{
- "name": "{{ vendor }}/{{ moduleKey }}",
- "description": "",
+ "name": "{{ modulePackageName }}",
+ "description": "{{ moduleName }} module",
+ "version": "1.0.0",
"authors": [
{
"name": "{{ authorName }}",
@@ -9,7 +10,20 @@
],
"autoload": {
"psr-4": {
- "{{ moduleNamespace }}\\": ""
+ "{{ moduleNamespace }}\\": "src/",
+ "{{ moduleNamespace }}\\Database\\Factories\\": "database/factories/",
+ "{{ moduleNamespace }}\\Database\\Seeders\\": "database/seeders/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "{{ moduleNamespace }}\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [],
+ "aliases": {}
}
}
}
diff --git a/src/Commands/Generators/stubs/controller/api.stub b/src/Commands/Generators/stubs/controller/api.stub
index bb986f5..6523cc4 100644
--- a/src/Commands/Generators/stubs/controller/api.stub
+++ b/src/Commands/Generators/stubs/controller/api.stub
@@ -2,9 +2,13 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Controllers\ApiController;
+use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
+use Illuminate\Foundation\Bus\DispatchesJobs;
+use Illuminate\Foundation\Validation\ValidatesRequests;
+use Illuminate\Routing\Controller;
+use Laraneat\Modules\Support\Concerns\WithJsonResponseHelpers;
-class {{ class }} extends ApiController
+class {{ class }} extends Controller
{
- //
+ use AuthorizesRequests, DispatchesJobs, ValidatesRequests, WithJsonResponseHelpers;
}
diff --git a/src/Commands/Generators/stubs/controller/web.stub b/src/Commands/Generators/stubs/controller/web.stub
index 91e2189..09114c6 100644
--- a/src/Commands/Generators/stubs/controller/web.stub
+++ b/src/Commands/Generators/stubs/controller/web.stub
@@ -2,9 +2,12 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Controllers\WebController;
+use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
+use Illuminate\Foundation\Bus\DispatchesJobs;
+use Illuminate\Foundation\Validation\ValidatesRequests;
+use Illuminate\Routing\Controller;
-class {{ class }} extends WebController
+class {{ class }} extends Controller
{
- //
+ use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}
diff --git a/src/Commands/Generators/stubs/dto.stub b/src/Commands/Generators/stubs/dto.stub
new file mode 100644
index 0000000..5d127b7
--- /dev/null
+++ b/src/Commands/Generators/stubs/dto.stub
@@ -0,0 +1,13 @@
+|{{ model }} create($attributes = [], ?{{ model }} $parent = null)
+ * @method \Illuminate\Support\Collection createMany(iterable $records)
* @method {{ model }} createOne($attributes = [])
- * @method \Illuminate\Support\Collection|{{ model }} make($attributes = [], ?{{ model }} $parent = null)
+ * @method \Illuminate\Support\Collection|{{ model }} make($attributes = [], ?{{ model }} $parent = null)
* @method {{ model }} makeOne($attributes = [])
*/
class {{ class }} extends Factory
@@ -17,7 +17,7 @@ class {{ class }} extends Factory
/**
* The name of the factory's corresponding model.
*
- * @var string
+ * @var class-string
*/
protected $model = {{ model }}::class;
@@ -31,4 +31,3 @@ class {{ class }} extends Factory
];
}
}
-
diff --git a/src/Commands/Generators/stubs/job/plain.stub b/src/Commands/Generators/stubs/job/plain.stub
index 0d579ca..a539371 100644
--- a/src/Commands/Generators/stubs/job/plain.stub
+++ b/src/Commands/Generators/stubs/job/plain.stub
@@ -2,13 +2,15 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Jobs\Job;
use Illuminate\Foundation\Bus\Dispatchable;
-class {{ class }} extends Job
+class {{ class }}
{
use Dispatchable;
+ /**
+ * Create a new job instance.
+ */
public function __construct()
{
//
diff --git a/src/Commands/Generators/stubs/job/queued.stub b/src/Commands/Generators/stubs/job/queued.stub
index e62208e..9a7cec5 100644
--- a/src/Commands/Generators/stubs/job/queued.stub
+++ b/src/Commands/Generators/stubs/job/queued.stub
@@ -2,17 +2,19 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Jobs\Job;
use Illuminate\Bus\Queueable;
-use Illuminate\Queue\SerializesModels;
-use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
-class {{ class }} extends Job implements ShouldQueue
+class {{ class }} implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+ /**
+ * Create a new job instance.
+ */
public function __construct()
{
//
diff --git a/src/Commands/Generators/stubs/listener/plain.stub b/src/Commands/Generators/stubs/listener/plain.stub
index 562fefb..6d96bd8 100755
--- a/src/Commands/Generators/stubs/listener/plain.stub
+++ b/src/Commands/Generators/stubs/listener/plain.stub
@@ -2,11 +2,13 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Listeners\Listener;
use {{ eventNamespace }}\{{ event }};
-class {{ class }} extends Listener
+class {{ class }}
{
+ /**
+ * Create the event listener.
+ */
public function __construct()
{
//
diff --git a/src/Commands/Generators/stubs/listener/queued.stub b/src/Commands/Generators/stubs/listener/queued.stub
index 374ed50..65f0bc2 100755
--- a/src/Commands/Generators/stubs/listener/queued.stub
+++ b/src/Commands/Generators/stubs/listener/queued.stub
@@ -2,15 +2,17 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Listeners\Listener;
use {{ eventNamespace }}\{{ event }};
-use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Queue\InteractsWithQueue;
-class {{ class }} extends Listener implements ShouldQueue
+class {{ class }} implements ShouldQueue
{
use InteractsWithQueue;
+ /**
+ * Create the event listener.
+ */
public function __construct()
{
//
diff --git a/src/Commands/Generators/stubs/mail.stub b/src/Commands/Generators/stubs/mail.stub
new file mode 100644
index 0000000..8633302
--- /dev/null
+++ b/src/Commands/Generators/stubs/mail.stub
@@ -0,0 +1,52 @@
+
+ */
+ public function attachments(): array
+ {
+ return [];
+ }
+}
diff --git a/src/Commands/Generators/stubs/mail/plain.stub b/src/Commands/Generators/stubs/mail/plain.stub
deleted file mode 100644
index 898db1a..0000000
--- a/src/Commands/Generators/stubs/mail/plain.stub
+++ /dev/null
@@ -1,24 +0,0 @@
-view('view.name');
- }
-}
diff --git a/src/Commands/Generators/stubs/mail/queued.stub b/src/Commands/Generators/stubs/mail/queued.stub
deleted file mode 100644
index 47ed21c..0000000
--- a/src/Commands/Generators/stubs/mail/queued.stub
+++ /dev/null
@@ -1,26 +0,0 @@
-view('view.name');
- }
-}
diff --git a/src/Commands/Generators/stubs/middleware.stub b/src/Commands/Generators/stubs/middleware.stub
index b234b14..323c213 100755
--- a/src/Commands/Generators/stubs/middleware.stub
+++ b/src/Commands/Generators/stubs/middleware.stub
@@ -2,16 +2,18 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Middleware\Middleware;
use Closure;
use Illuminate\Http\Request;
+use Symfony\Component\HttpFoundation\Response;
-class {{ class }} extends Middleware
+class {{ class }}
{
/**
* Handle an incoming request.
+ *
+ * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
- public function handle(Request $request, Closure $next)
+ public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
diff --git a/src/Commands/Generators/stubs/model/full.stub b/src/Commands/Generators/stubs/model/full.stub
index aa1a955..39d7bf9 100644
--- a/src/Commands/Generators/stubs/model/full.stub
+++ b/src/Commands/Generators/stubs/model/full.stub
@@ -2,10 +2,10 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Models\Model;
+use {{ factoryNamespace }}\{{ factory }};
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Factories\Factory;
-use {{ factoryNamespace }}\{{ factory }};
+use Illuminate\Database\Eloquent\Model;
class {{ class }} extends Model
{
diff --git a/src/Commands/Generators/stubs/model/plain.stub b/src/Commands/Generators/stubs/model/plain.stub
index 90b8d19..279313e 100644
--- a/src/Commands/Generators/stubs/model/plain.stub
+++ b/src/Commands/Generators/stubs/model/plain.stub
@@ -2,7 +2,7 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Models\Model;
+use Illuminate\Database\Eloquent\Model;
class {{ class }} extends Model
{
diff --git a/src/Commands/Generators/stubs/module.json.stub b/src/Commands/Generators/stubs/module.json.stub
deleted file mode 100755
index 532fd74..0000000
--- a/src/Commands/Generators/stubs/module.json.stub
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "{{ moduleName }}",
- "namespace": "{{ moduleNamespace }}",
- "alias": "{{ moduleKey }}",
- "description": "{{ moduleName }} module",
- "keywords": [],
- "priority": 0,
- "providers": [],
- "aliases": {},
- "files": [],
- "requires": []
-}
diff --git a/src/Commands/Generators/stubs/notification/plain.stub b/src/Commands/Generators/stubs/notification/plain.stub
index d7fbd9f..240ef66 100644
--- a/src/Commands/Generators/stubs/notification/plain.stub
+++ b/src/Commands/Generators/stubs/notification/plain.stub
@@ -2,19 +2,32 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Notifications\Notification;
+use Illuminate\Notifications\Notification;
class {{ class }} extends Notification
{
+ /**
+ * Create a new notification instance.
+ */
public function __construct()
{
//
}
+ /**
+ * Get the notification's delivery channels.
+ *
+ * @return array
+ */
+ public function via(object $notifiable): array
+ {
+ return ['mail', 'database'];
+ }
+
/**
* Get the array representation of the notification.
*/
- public function toArray($notifiable): array
+ public function toArray(object $notifiable): array
{
return [
//
diff --git a/src/Commands/Generators/stubs/notification/queued.stub b/src/Commands/Generators/stubs/notification/queued.stub
index 8c16dac..d4d0905 100644
--- a/src/Commands/Generators/stubs/notification/queued.stub
+++ b/src/Commands/Generators/stubs/notification/queued.stub
@@ -2,15 +2,18 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Notifications\Notification;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
+use Illuminate\Notifications\Notification;
class {{ class }} extends Notification implements ShouldQueue
{
use Queueable;
+ /**
+ * Create a new notification instance.
+ */
public function __construct()
{
//
@@ -18,8 +21,10 @@ class {{ class }} extends Notification implements ShouldQueue
/**
* Get the notification's delivery channels.
+ *
+ * @return array
*/
- public function via($notifiable): array
+ public function via(object $notifiable): array
{
return ['mail'];
}
@@ -27,18 +32,20 @@ class {{ class }} extends Notification implements ShouldQueue
/**
* Get the mail representation of the notification.
*/
- public function toMail($notifiable): MailMessage
+ public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->line('The introduction to the notification.')
- ->action('Notification Action', 'https://laravel.com')
+ ->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
+ *
+ * @return array
*/
- public function toArray($notifiable): array
+ public function toArray(object $notifiable): array
{
return [
//
diff --git a/src/Commands/Generators/stubs/observer.stub b/src/Commands/Generators/stubs/observer.stub
index 1d29d41..cff4f33 100644
--- a/src/Commands/Generators/stubs/observer.stub
+++ b/src/Commands/Generators/stubs/observer.stub
@@ -2,15 +2,14 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Observers\Observer;
use {{ modelNamespace }}\{{ model }};
-class {{ class }} extends Observer
+class {{ class }}
{
/**
* Handle the {{ model }} "created" event.
*/
- public function created({{ model }} ${{ modelEntity }}): void
+ public function created({{ model }} ${{ modelCamelCase }}): void
{
//
}
@@ -18,7 +17,7 @@ class {{ class }} extends Observer
/**
* Handle the {{ model }} "updated" event.
*/
- public function updated({{ model }} ${{ modelEntity }}): void
+ public function updated({{ model }} ${{ modelCamelCase }}): void
{
//
}
@@ -26,7 +25,7 @@ class {{ class }} extends Observer
/**
* Handle the {{ model }} "deleted" event.
*/
- public function deleted({{ model }} ${{ modelEntity }}): void
+ public function deleted({{ model }} ${{ modelCamelCase }}): void
{
//
}
@@ -34,7 +33,7 @@ class {{ class }} extends Observer
/**
* Handle the {{ model }} "restored" event.
*/
- public function restored({{ model }} ${{ modelEntity }}): void
+ public function restored({{ model }} ${{ modelCamelCase }}): void
{
//
}
@@ -42,7 +41,7 @@ class {{ class }} extends Observer
/**
* Handle the {{ model }} "force deleted" event.
*/
- public function forceDeleted({{ model }} ${{ modelEntity }}): void
+ public function forceDeleted({{ model }} ${{ modelCamelCase }}): void
{
//
}
diff --git a/src/Commands/Generators/stubs/policy/full.stub b/src/Commands/Generators/stubs/policy/full.stub
index 0aa6861..7193c8c 100644
--- a/src/Commands/Generators/stubs/policy/full.stub
+++ b/src/Commands/Generators/stubs/policy/full.stub
@@ -2,29 +2,26 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Policies\Policy;
-use Illuminate\Auth\Access\HandlesAuthorization;
use {{ modelNamespace }}\{{ model }};
use {{ userNamespace }}\{{ user }};
-class {{ class }} extends Policy
+class {{ class }}
{
- use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*/
public function viewAny({{ user }} $user): bool
{
- return $user->can('view-{{ modelPermissionEntity }}');
+ return $user->can('view-{{ modelKebabCase }}');
}
/**
* Determine whether the user can view the model.
*/
- public function view({{ user }} $user, {{ model }} ${{ modelEntity }}): bool
+ public function view({{ user }} $user, {{ model }} ${{ modelCamelCase }}): bool
{
- return $user->can('view-{{ modelPermissionEntity }}');
+ return $user->can('view-{{ modelKebabCase }}');
}
/**
@@ -32,38 +29,38 @@ class {{ class }} extends Policy
*/
public function create({{ user }} $user): bool
{
- return $user->can('create-{{ modelPermissionEntity }}');
+ return $user->can('create-{{ modelKebabCase }}');
}
/**
* Determine whether the user can update the model.
*/
- public function update({{ user }} $user, {{ model }} ${{ modelEntity }}): bool
+ public function update({{ user }} $user, {{ model }} ${{ modelCamelCase }}): bool
{
- return $user->can('update-{{ modelPermissionEntity }}');
+ return $user->can('update-{{ modelKebabCase }}');
}
/**
* Determine whether the user can delete the model.
*/
- public function delete({{ user }} $user, {{ model }} ${{ modelEntity }}): bool
+ public function delete({{ user }} $user, {{ model }} ${{ modelCamelCase }}): bool
{
- return $user->can('delete-{{ modelPermissionEntity }}');
+ return $user->can('delete-{{ modelKebabCase }}');
}
/**
* Determine whether the user can restore the model.
*/
- public function restore({{ user }} $user, {{ model }} ${{ modelEntity }}): bool
+ public function restore({{ user }} $user, {{ model }} ${{ modelCamelCase }}): bool
{
- return $user->can('delete-{{ modelPermissionEntity }}');
+ return $user->can('delete-{{ modelKebabCase }}');
}
/**
* Determine whether the user can permanently delete the model.
*/
- public function forceDelete({{ user }} $user, {{ model }} ${{ modelEntity }}): bool
+ public function forceDelete({{ user }} $user, {{ model }} ${{ modelCamelCase }}): bool
{
- return $user->can('force-delete-{{ modelPermissionEntity }}');
+ return $user->can('force-delete-{{ modelKebabCase }}');
}
}
diff --git a/src/Commands/Generators/stubs/policy/plain.stub b/src/Commands/Generators/stubs/policy/plain.stub
index b4ceb60..e2506b7 100644
--- a/src/Commands/Generators/stubs/policy/plain.stub
+++ b/src/Commands/Generators/stubs/policy/plain.stub
@@ -2,15 +2,7 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Policies\Policy;
-use Illuminate\Auth\Access\HandlesAuthorization;
-
-class {{ class }} extends Policy
+class {{ class }}
{
- use HandlesAuthorization;
-
- public function __construct()
- {
- //
- }
+ //
}
diff --git a/src/Commands/Generators/stubs/provider/event.stub b/src/Commands/Generators/stubs/provider/event.stub
index 4667946..fdd9935 100644
--- a/src/Commands/Generators/stubs/provider/event.stub
+++ b/src/Commands/Generators/stubs/provider/event.stub
@@ -2,12 +2,14 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Providers\EventServiceProvider as ServiceProvider;
+use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class {{ class }} extends ServiceProvider
{
/**
- * The event listener mappings for the application.
+ * The event handler mappings for the application.
+ *
+ * @var array>
*/
protected $listen = [];
diff --git a/src/Commands/Generators/stubs/provider/module.stub b/src/Commands/Generators/stubs/provider/module.stub
index 6f73860..429cd9d 100644
--- a/src/Commands/Generators/stubs/provider/module.stub
+++ b/src/Commands/Generators/stubs/provider/module.stub
@@ -2,22 +2,16 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Providers\ServiceProvider;
-use Laraneat\Modules\Traits\ModuleProviderHelpersTrait;
+use Laraneat\Modules\Support\ModuleServiceProvider;
-class {{ class }} extends ServiceProvider
+class {{ class }} extends ModuleServiceProvider
{
- use ModuleProviderHelpersTrait;
-
- protected string $moduleName = '{{ moduleName }}';
- protected string $moduleKey = '{{ moduleKey }}';
-
/**
* Register services.
*/
public function register(): void
{
- //
+ // $this->loadConfigurations();
}
/**
@@ -25,75 +19,84 @@ class {{ class }} extends ServiceProvider
*/
public function boot(): void
{
- $this->registerMigrations();
- // $this->registerTranslations();
- // $this->registerCommands();
- // $this->registerViews();
+ $this->loadMigrations();
+ // $this->loadCommands();
+ // $this->loadTranslations();
+ // $this->loadViews();
}
/**
- * Get the services provided by the provider.
+ * Register configuration files.
*/
- public function provides(): array
+ public function loadConfigurations(): void
{
- return [];
+ $sourcePath = __DIR__.'/{{ configPath }}/{{ moduleNameKebabCase }}.php';
+ $configsPath = $this->app->configPath('{{ moduleNameKebabCase }}.php');
+
+ $this->mergeConfigFrom($sourcePath, '{{ moduleNameKebabCase }}');
+
+ $this->publishes([
+ $sourcePath => $configsPath
+ ], '{{ moduleNameKebabCase }}-config');
}
/**
- * Register translations.
+ * Register migrations.
*/
- public function registerTranslations(): void
+ public function loadMigrations(): void
{
- $sourcePath = module_path($this->moduleName, '{{ langPath }}');
- $langPath = resource_path('lang/modules/' . $this->moduleKey);
+ $sourcePath = __DIR__.'/{{ migrationsPath }}';
+ $migrationsPath = $this->app->databasePath('migrations');
- $this->loadTranslationsFrom($sourcePath, $this->moduleKey);
+ $this->loadMigrationsFrom($sourcePath);
$this->publishes([
- $sourcePath => $langPath,
- ], 'translations');
+ $sourcePath => $migrationsPath
+ ], '{{ moduleNameKebabCase }}-migrations');
}
/**
- * Register views.
+ * Register artisan commands.
*/
- public function registerViews(): void
+ public function loadCommands(): void
{
- $sourcePath = module_path($this->moduleName, '{{ viewsPath }}');
- $viewsPath = resource_path('views/modules/' . $this->moduleKey);
-
- $this->loadViewsFrom(
- array_merge($this->getPublishableViewPaths($this->moduleKey), [$sourcePath]),
- $this->moduleKey
- );
-
- $this->publishes([
- $sourcePath => $viewsPath
- ], 'views');
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ '{{ commandsNamespace }}' => __DIR__.'/{{ commandsPath }}',
+ ]);
+ }
}
/**
- * Register migrations.
+ * Register translations.
*/
- public function registerMigrations(): void
+ public function loadTranslations(): void
{
- $sourcePath = module_path($this->moduleName, '{{ migrationsPath }}');
- $migrationsPath = database_path('migrations');
+ $sourcePath = __DIR__.'/{{ langPath }}';
+ $langPath = $this->app->langPath('modules/{{ moduleNameKebabCase }}');
- $this->loadMigrationsFrom($sourcePath);
+ $this->loadTranslationsFrom($sourcePath, '{{ moduleNameKebabCase }}');
$this->publishes([
- $sourcePath => $migrationsPath
- ], 'migrations');
+ $sourcePath => $langPath,
+ ], '{{ moduleNameKebabCase }}-translations');
}
/**
- * Register artisan commands.
+ * Register views.
*/
- public function registerCommands(): void
+ public function loadViews(): void
{
- if ($this->app->runningInConsole()) {
- $this->loadCommands(module_path($this->moduleName, '{{ commandsPath }}'));
- }
+ $sourcePath = __DIR__.'/{{ viewsPath }}';
+ $viewsPath = $this->app->resourcePath('views/modules/{{ moduleNameKebabCase }}');
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths('{{ moduleNameKebabCase }}'), [$sourcePath]),
+ '{{ moduleNameKebabCase }}'
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath
+ ], '{{ moduleNameKebabCase }}-views');
}
}
diff --git a/src/Commands/Generators/stubs/provider/plain.stub b/src/Commands/Generators/stubs/provider/plain.stub
index 4f35cc2..537ce0a 100644
--- a/src/Commands/Generators/stubs/provider/plain.stub
+++ b/src/Commands/Generators/stubs/provider/plain.stub
@@ -2,12 +2,12 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Providers\ServiceProvider;
+use Illuminate\Support\ServiceProvider;
class {{ class }} extends ServiceProvider
{
/**
- * Bootstrap services.
+ * Register services.
*/
public function register(): void
{
diff --git a/src/Commands/Generators/stubs/provider/route.stub b/src/Commands/Generators/stubs/provider/route.stub
index bf97cd2..a5e1af7 100644
--- a/src/Commands/Generators/stubs/provider/route.stub
+++ b/src/Commands/Generators/stubs/provider/route.stub
@@ -2,15 +2,13 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Providers\RouteServiceProvider as ServiceProvider;
+use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
-use Laraneat\Modules\Traits\RouteProviderHelpersTrait;
+use Laraneat\Modules\Support\Concerns\CanLoadRoutesFromDirectory;
class {{ class }} extends ServiceProvider
{
- use RouteProviderHelpersTrait;
-
- protected string $moduleName = '{{ moduleName }}';
+ use CanLoadRoutesFromDirectory;
/**
* Called before routes are registered.
@@ -37,9 +35,9 @@ class {{ class }} extends ServiceProvider
protected function mapWebRoutes(): void
{
Route::middleware('web')
-// ->namespace('{{ webControllerNamespace }}')
+ // ->namespace('{{ webControllerNamespace }}')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, '{{ webRoutesPath }}'));
+ $this->loadRoutesFromDirectory(__DIR__.'/{{ webRoutesPath }}');
});
}
@@ -51,9 +49,9 @@ class {{ class }} extends ServiceProvider
{
Route::prefix('api')
->middleware('api')
-// ->namespace('{{ apiControllerNamespace }}')
+ // ->namespace('{{ apiControllerNamespace }}')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, '{{ apiRoutesPath }}'));
+ $this->loadRoutesFromDirectory(__DIR__.'/{{ apiRoutesPath }}');
});
}
}
diff --git a/src/Commands/Generators/stubs/query-wizard/elastic.stub b/src/Commands/Generators/stubs/query-wizard/elastic.stub
deleted file mode 100644
index c87f673..0000000
--- a/src/Commands/Generators/stubs/query-wizard/elastic.stub
+++ /dev/null
@@ -1,78 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/src/Commands/Generators/stubs/query-wizard/eloquent.stub b/src/Commands/Generators/stubs/query-wizard/eloquent.stub
index 6e9e3ca..a001698 100644
--- a/src/Commands/Generators/stubs/query-wizard/eloquent.stub
+++ b/src/Commands/Generators/stubs/query-wizard/eloquent.stub
@@ -2,7 +2,7 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\QueryWizards\EloquentQueryWizard;
+use Jackardios\QueryWizard\Eloquent\EloquentQueryWizard;
use Jackardios\QueryWizard\Eloquent\EloquentFilter;
use Jackardios\QueryWizard\Eloquent\EloquentInclude;
use Jackardios\QueryWizard\Eloquent\EloquentSort;
@@ -10,7 +10,7 @@ use Jackardios\QueryWizard\Eloquent\EloquentSort;
class {{ class }} extends EloquentQueryWizard
{
/**
- * @return array
+ * @return array
*/
protected function allowedAppends(): array
{
@@ -18,7 +18,7 @@ class {{ class }} extends EloquentQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function defaultAppends(): array
{
@@ -26,7 +26,7 @@ class {{ class }} extends EloquentQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function allowedFields(): array
{
@@ -36,7 +36,7 @@ class {{ class }} extends EloquentQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function allowedFilters(): array
{
@@ -44,7 +44,7 @@ class {{ class }} extends EloquentQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function allowedIncludes(): array
{
@@ -52,7 +52,7 @@ class {{ class }} extends EloquentQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function defaultIncludes(): array
{
@@ -60,7 +60,7 @@ class {{ class }} extends EloquentQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function allowedSorts(): array
{
@@ -68,7 +68,7 @@ class {{ class }} extends EloquentQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function defaultSorts(): array
{
diff --git a/src/Commands/Generators/stubs/query-wizard/model.stub b/src/Commands/Generators/stubs/query-wizard/model.stub
index 10b986d..2b878ef 100644
--- a/src/Commands/Generators/stubs/query-wizard/model.stub
+++ b/src/Commands/Generators/stubs/query-wizard/model.stub
@@ -2,13 +2,13 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\QueryWizards\ModelQueryWizard;
+use Jackardios\QueryWizard\Model\ModelQueryWizard;
use Jackardios\QueryWizard\Model\ModelInclude;
class {{ class }} extends ModelQueryWizard
{
/**
- * @return array
+ * @return array
*/
protected function allowedAppends(): array
{
@@ -16,7 +16,7 @@ class {{ class }} extends ModelQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function defaultAppends(): array
{
@@ -24,7 +24,7 @@ class {{ class }} extends ModelQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function allowedFields(): array
{
@@ -34,7 +34,7 @@ class {{ class }} extends ModelQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function allowedIncludes(): array
{
@@ -42,7 +42,7 @@ class {{ class }} extends ModelQueryWizard
}
/**
- * @return array
+ * @return array
*/
protected function defaultIncludes(): array
{
diff --git a/src/Commands/Generators/stubs/query-wizard/scout.stub b/src/Commands/Generators/stubs/query-wizard/scout.stub
deleted file mode 100644
index 947daeb..0000000
--- a/src/Commands/Generators/stubs/query-wizard/scout.stub
+++ /dev/null
@@ -1,77 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/src/Commands/Generators/stubs/readme.stub b/src/Commands/Generators/stubs/readme.stub
deleted file mode 100644
index be4bf30..0000000
--- a/src/Commands/Generators/stubs/readme.stub
+++ /dev/null
@@ -1 +0,0 @@
-# [Laraneat](https://github.com/laraneat/laraneat) {{ moduleName }} module
diff --git a/src/Commands/Generators/stubs/request/create.stub b/src/Commands/Generators/stubs/request/create.stub
index 6e3cf3f..1a2bc08 100644
--- a/src/Commands/Generators/stubs/request/create.stub
+++ b/src/Commands/Generators/stubs/request/create.stub
@@ -2,12 +2,12 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Requests\Request;
use {{ dtoNamespace }}\{{ dto }};
use {{ modelNamespace }}\{{ model }};
+use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
-class {{ class }} extends Request
+class {{ class }} extends FormRequest
{
public function rules(): array
{
@@ -23,6 +23,6 @@ class {{ class }} extends Request
public function toDTO(): {{ dto }}
{
- return new {{ dto }}($this->validated());
+ return {{ dto }}::from($this->validated());
}
}
diff --git a/src/Commands/Generators/stubs/request/delete.stub b/src/Commands/Generators/stubs/request/delete.stub
index 6e43fbb..837e84f 100644
--- a/src/Commands/Generators/stubs/request/delete.stub
+++ b/src/Commands/Generators/stubs/request/delete.stub
@@ -2,10 +2,10 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Requests\Request;
+use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
-class {{ class }} extends Request
+class {{ class }} extends FormRequest
{
public function rules(): array
{
@@ -14,7 +14,7 @@ class {{ class }} extends Request
public function authorize(): bool
{
- ${{ modelEntity }} = $this->route('{{ modelEntity }}');
- return ${{ modelEntity }} && Gate::check('delete', ${{ modelEntity }});
+ ${{ modelCamelCase }} = $this->route('{{ modelCamelCase }}');
+ return ${{ modelCamelCase }} && Gate::check('delete', ${{ modelCamelCase }});
}
}
diff --git a/src/Commands/Generators/stubs/request/list.stub b/src/Commands/Generators/stubs/request/list.stub
index b04b420..8284481 100644
--- a/src/Commands/Generators/stubs/request/list.stub
+++ b/src/Commands/Generators/stubs/request/list.stub
@@ -2,11 +2,11 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Requests\Request;
use {{ modelNamespace }}\{{ model }};
+use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
-class {{ class }} extends Request
+class {{ class }} extends FormRequest
{
public function rules(): array
{
diff --git a/src/Commands/Generators/stubs/request/plain.stub b/src/Commands/Generators/stubs/request/plain.stub
index dc4d3b0..48ad628 100644
--- a/src/Commands/Generators/stubs/request/plain.stub
+++ b/src/Commands/Generators/stubs/request/plain.stub
@@ -2,9 +2,9 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Requests\Request;
+use Illuminate\Foundation\Http\FormRequest;
-class {{ class }} extends Request
+class {{ class }} extends FormRequest
{
public function rules(): array
{
diff --git a/src/Commands/Generators/stubs/request/update.stub b/src/Commands/Generators/stubs/request/update.stub
index 45e79b3..00da57c 100644
--- a/src/Commands/Generators/stubs/request/update.stub
+++ b/src/Commands/Generators/stubs/request/update.stub
@@ -2,11 +2,11 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Requests\Request;
use {{ dtoNamespace }}\{{ dto }};
+use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
-class {{ class }} extends Request
+class {{ class }} extends FormRequest
{
public function rules(): array
{
@@ -17,12 +17,12 @@ class {{ class }} extends Request
public function authorize(): bool
{
- ${{ modelEntity }} = $this->route('{{ modelEntity }}');
- return ${{ modelEntity }} && Gate::check('update', ${{ modelEntity }});
+ ${{ modelCamelCase }} = $this->route('{{ modelCamelCase }}');
+ return ${{ modelCamelCase }} && Gate::check('update', ${{ modelCamelCase }});
}
public function toDTO(): {{ dto }}
{
- return new {{ dto }}($this->validated());
+ return {{ dto }}::from($this->validated());
}
}
diff --git a/src/Commands/Generators/stubs/request/view.stub b/src/Commands/Generators/stubs/request/view.stub
index 6d827cf..e5c4e85 100644
--- a/src/Commands/Generators/stubs/request/view.stub
+++ b/src/Commands/Generators/stubs/request/view.stub
@@ -2,10 +2,10 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Requests\Request;
+use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;
-class {{ class }} extends Request
+class {{ class }} extends FormRequest
{
public function rules(): array
{
@@ -14,7 +14,7 @@ class {{ class }} extends Request
public function authorize(): bool
{
- ${{ modelEntity }} = $this->route('{{ modelEntity }}');
- return ${{ modelEntity }} && Gate::check('view', ${{ modelEntity }});
+ ${{ modelCamelCase }} = $this->route('{{ modelCamelCase }}');
+ return ${{ modelCamelCase }} && Gate::check('view', ${{ modelCamelCase }});
}
}
diff --git a/src/Commands/Generators/stubs/resource/collection.stub b/src/Commands/Generators/stubs/resource/collection.stub
index e1284ed..88f416b 100644
--- a/src/Commands/Generators/stubs/resource/collection.stub
+++ b/src/Commands/Generators/stubs/resource/collection.stub
@@ -2,17 +2,15 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Resources\Json\ResourceCollection;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\ResourceCollection;
class {{ class }} extends ResourceCollection
{
/**
* Transform the resource collection into an array.
- *
- * @param \Illuminate\Http\Request $request
- * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
- public function toArray($request)
+ public function toArray(Request $request): array
{
return parent::toArray($request);
}
diff --git a/src/Commands/Generators/stubs/resource/single.stub b/src/Commands/Generators/stubs/resource/single.stub
index 5997330..e55a05e 100644
--- a/src/Commands/Generators/stubs/resource/single.stub
+++ b/src/Commands/Generators/stubs/resource/single.stub
@@ -2,17 +2,15 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Resources\Json\JsonResource;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
class {{ class }} extends JsonResource
{
/**
* Transform the resource into an array.
- *
- * @param \Illuminate\Http\Request $request
- * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
- public function toArray($request)
+ public function toArray(Request $request): array
{
return parent::toArray($request);
}
diff --git a/src/Commands/Generators/stubs/rule.stub b/src/Commands/Generators/stubs/rule.stub
index 719a753..e54d7ef 100755
--- a/src/Commands/Generators/stubs/rule.stub
+++ b/src/Commands/Generators/stubs/rule.stub
@@ -2,34 +2,18 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Rules\Rule;
+use Closure;
+use Illuminate\Contracts\Validation\ValidationRule;
-class {{ class }} extends Rule
+class {{ class }} implements ValidationRule
{
- public function __construct()
- {
- //
- }
-
/**
- * Determine if the validation rule passes.
+ * Run the validation rule.
*
- * @param string $attribute
- * @param mixed $value
- * @return bool
+ * @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
- public function passes($attribute, $value)
+ public function validate(string $attribute, mixed $value, Closure $fail): void
{
//
}
-
- /**
- * Get the validation error message.
- *
- * @return string|array
- */
- public function message()
- {
- return 'The validation error message.';
- }
}
diff --git a/src/Commands/Generators/stubs/seeder/permissions.stub b/src/Commands/Generators/stubs/seeder/permissions.stub
index 136e4ef..13772a5 100644
--- a/src/Commands/Generators/stubs/seeder/permissions.stub
+++ b/src/Commands/Generators/stubs/seeder/permissions.stub
@@ -2,9 +2,9 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Seeders\Seeder;
-use {{ actionNamespace }}\{{ createPermissionAction }};
-use {{ dtoNamespace }}\{{ createPermissionDTO }};
+use {{ createPermissionActionNamespace }}\{{ createPermissionAction }};
+use {{ createPermissionDTONamespace }}\{{ createPermissionDTO }};
+use Illuminate\Database\Seeder;
class {{ class }} extends Seeder
{
@@ -13,33 +13,33 @@ class {{ class }} extends Seeder
$createPermissionAction = {{ createPermissionAction }}::make();
$createPermissionAction->handle(new {{ createPermissionDTO }}(
- name: 'view-{{ modelPermissionEntity }}',
- display_name: 'View any "{{ modelPermissionEntities }}"',
- group: '{{ modelPermissionEntities }}'
+ name: 'view-{{ modelKebabCase }}',
+ display_name: 'View any "{{ modelsKebabCase }}"',
+ group: '{{ modelsKebabCase }}'
));
$createPermissionAction->handle(new {{ createPermissionDTO }}(
- name: 'create-{{ modelPermissionEntity }}',
- display_name: 'Create "{{ modelPermissionEntities }}"',
- group: '{{ modelPermissionEntities }}'
+ name: 'create-{{ modelKebabCase }}',
+ display_name: 'Create "{{ modelsKebabCase }}"',
+ group: '{{ modelsKebabCase }}'
));
$createPermissionAction->handle(new {{ createPermissionDTO }}(
- name: 'update-{{ modelPermissionEntity }}',
- display_name: 'Update any "{{ modelPermissionEntities }}"',
- group: '{{ modelPermissionEntities }}'
+ name: 'update-{{ modelKebabCase }}',
+ display_name: 'Update any "{{ modelsKebabCase }}"',
+ group: '{{ modelsKebabCase }}'
));
$createPermissionAction->handle(new {{ createPermissionDTO }}(
- name: 'delete-{{ modelPermissionEntity }}',
- display_name: 'Delete any "{{ modelPermissionEntities }}"',
- group: '{{ modelPermissionEntities }}'
+ name: 'delete-{{ modelKebabCase }}',
+ display_name: 'Delete any "{{ modelsKebabCase }}"',
+ group: '{{ modelsKebabCase }}'
));
$createPermissionAction->handle(new {{ createPermissionDTO }}(
- name: 'force-delete-{{ modelPermissionEntity }}',
- display_name: 'Force delete any "{{ modelPermissionEntities }}"',
- group: '{{ modelPermissionEntities }}'
+ name: 'force-delete-{{ modelKebabCase }}',
+ display_name: 'Force delete any "{{ modelsKebabCase }}"',
+ group: '{{ modelsKebabCase }}'
));
}
}
diff --git a/src/Commands/Generators/stubs/seeder/plain.stub b/src/Commands/Generators/stubs/seeder/plain.stub
index 613b56b..e8c583f 100644
--- a/src/Commands/Generators/stubs/seeder/plain.stub
+++ b/src/Commands/Generators/stubs/seeder/plain.stub
@@ -2,7 +2,7 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Seeders\Seeder;
+use Illuminate\Database\Seeder;
class {{ class }} extends Seeder
{
diff --git a/src/Commands/Generators/stubs/test/api/create.stub b/src/Commands/Generators/stubs/test/api/create.stub
index 9d897b6..eab8d18 100644
--- a/src/Commands/Generators/stubs/test/api/create.stub
+++ b/src/Commands/Generators/stubs/test/api/create.stub
@@ -2,34 +2,30 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
-use Illuminate\Testing\Fluent\AssertableJson;
use {{ modelNamespace }}\{{ model }};
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Testing\Fluent\AssertableJson;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group api
*/
class {{ class }} extends TestCase
{
+ use RefreshDatabase;
+
/**
* Roles and permissions, to be attached on the user by default
*/
- protected array $access = [
- 'permissions' => 'create-{{ modelPermissionEntity }}',
- 'roles' => '',
+ protected array $testUserAccess = [
+ 'permissions' => 'create-{{ modelKebabCase }}',
+ 'roles' => '',
];
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_create_{{ modelSnake }}(): void
+ public function test_create_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
$data = $this->getTestData();
@@ -40,19 +36,45 @@ class {{ class }} extends TestCase
$json->has('id')
->whereAll($data)
->etc()
- )
+ )
);
- $this->assertExistsModelWhereColumns({{ model }}::class, $data);
+ $this->assertDatabaseHas({{ model }}::class, $data);
}
- public function test_create_{{ modelSnake }}_without_access(): void
+ public function test_create_{{ modelSnakeCase }}_with_invalid_data(): void
{
- $this->getTestingUserWithoutAccess();
+ $this->actingAsTestUser();
+
+ $this->postJson(route('{{ routeName }}'), [])
+ ->assertUnprocessable()
+ ->assertJsonValidationErrors([
+ // TODO: add expected validation errors here
+ ]);
+ }
+
+ public function test_create_{{ modelSnakeCase }}_unauthenticated(): void
+ {
+ $data = $this->getTestData();
+
+ $this->postJson(route('{{ routeName }}'), $data)
+ ->assertUnauthorized();
+ }
+
+ public function test_create_{{ modelSnakeCase }}_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
$data = $this->getTestData();
$this->postJson(route('{{ routeName }}'), $data)
->assertForbidden();
}
+
+ protected function getTestData(array $mergeData = []): array
+ {
+ return array_merge([
+ // TODO: add fields here
+ ], $mergeData);
+ }
}
diff --git a/src/Commands/Generators/stubs/test/api/delete.stub b/src/Commands/Generators/stubs/test/api/delete.stub
index 6c1b6ae..412c5df 100644
--- a/src/Commands/Generators/stubs/test/api/delete.stub
+++ b/src/Commands/Generators/stubs/test/api/delete.stub
@@ -2,50 +2,61 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
use {{ modelNamespace }}\{{ model }};
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group api
*/
class {{ class }} extends TestCase
{
+ use RefreshDatabase;
+
/**
* Roles and permissions, to be attached on the user by default
*/
- protected array $access = [
- 'permissions' => 'delete-{{ modelPermissionEntity }}',
- 'roles' => '',
+ protected array $testUserAccess = [
+ 'permissions' => 'delete-{{ modelKebabCase }}',
+ 'roles' => '',
];
- public function test_delete_{{ modelSnake }}(): void
+ public function test_delete_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
- ${{ modelEntity }} = {{ model }}::factory()->create();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
- $this->deleteJson(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]))
+ $this->deleteJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]))
->assertNoContent();
- $this->assertNull({{ model }}::find(${{ modelEntity }}->getKey()));
+ $this->assertNull({{ model }}::find(${{ modelCamelCase }}->getKey()));
+ }
+
+ public function test_delete_{{ modelSnakeCase }}_unauthenticated(): void
+ {
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
+
+ $this->deleteJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]))
+ ->assertUnauthorized();
}
- public function test_delete_{{ modelSnake }}_without_access(): void
+ public function test_delete_{{ modelSnakeCase }}_without_access(): void
{
- $this->getTestingUserWithoutAccess();
+ $this->actingAsTestUserWithoutAccess();
- ${{ modelEntity }} = {{ model }}::factory()->create();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
- $this->deleteJson(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]))
+ $this->deleteJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]))
->assertForbidden();
}
- public function test_delete_not_existing_{{ modelSnake }}(): void
+ public function test_delete_not_existing_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
- $this->deleteJson(route('{{ routeName }}', ['{{ modelEntity }}' => 7777]))
+ $this->deleteJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => 7777]))
->assertNotFound();
}
}
diff --git a/src/Commands/Generators/stubs/test/api/list.stub b/src/Commands/Generators/stubs/test/api/list.stub
index 4ae82a1..24871ee 100644
--- a/src/Commands/Generators/stubs/test/api/list.stub
+++ b/src/Commands/Generators/stubs/test/api/list.stub
@@ -2,28 +2,31 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
use {{ modelNamespace }}\{{ model }};
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group api
*/
class {{ class }} extends TestCase
{
+ use RefreshDatabase;
+
/**
* Roles and permissions, to be attached on the user by default
*/
- protected array $access = [
- 'permissions' => 'view-{{ modelPermissionEntity }}',
- 'roles' => '',
+ protected array $testUserAccess = [
+ 'permissions' => 'view-{{ modelKebabCase }}',
+ 'roles' => '',
];
- public function test_list_{{ modelsSnake }}(): void
+ public function test_list_{{ modelsSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
- {{ model }}::factory()->count(2)->create();
+ {{ model }}::factory()->count(3)->create();
$this->getJson(route('{{ routeName }}'))
->assertOk()
@@ -32,14 +35,22 @@ class {{ class }} extends TestCase
'meta',
'data'
])
- ->assertJsonCount({{ model }}::query()->count(), 'data');
+ ->assertJsonCount(3, 'data');
+ }
+
+ public function test_list_{{ modelsSnakeCase }}_unauthenticated(): void
+ {
+ {{ model }}::factory()->count(3)->create();
+
+ $this->getJson(route('{{ routeName }}'))
+ ->assertUnauthorized();
}
- public function test_list_{{ modelsSnake }}_without_access(): void
+ public function test_list_{{ modelsSnakeCase }}_without_access(): void
{
- $this->getTestingUserWithoutAccess();
+ $this->actingAsTestUserWithoutAccess();
- {{ model }}::factory()->count(2)->create();
+ {{ model }}::factory()->count(3)->create();
$this->getJson(route('{{ routeName }}'))
->assertForbidden();
diff --git a/src/Commands/Generators/stubs/test/api/plain.stub b/src/Commands/Generators/stubs/test/api/plain.stub
index 9cd9b44..f1b1c75 100644
--- a/src/Commands/Generators/stubs/test/api/plain.stub
+++ b/src/Commands/Generators/stubs/test/api/plain.stub
@@ -2,20 +2,23 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group api
*/
class {{ class }} extends TestCase
{
+ use RefreshDatabase;
+
/**
* Roles and permissions, to be attached on the user by default
*/
- protected array $access = [
+ protected array $testUserAccess = [
'permissions' => '',
- 'roles' => '',
+ 'roles' => '',
];
public function test(): void
diff --git a/src/Commands/Generators/stubs/test/api/update.stub b/src/Commands/Generators/stubs/test/api/update.stub
index d76a5f1..3ea2009 100644
--- a/src/Commands/Generators/stubs/test/api/update.stub
+++ b/src/Commands/Generators/stubs/test/api/update.stub
@@ -2,43 +2,39 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
-use Illuminate\Testing\Fluent\AssertableJson;
use {{ modelNamespace }}\{{ model }};
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Testing\Fluent\AssertableJson;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group api
*/
class {{ class }} extends TestCase
{
+ use RefreshDatabase;
+
/**
* Roles and permissions, to be attached on the user by default
*/
- protected array $access = [
- 'permissions' => 'update-{{ modelPermissionEntity }}',
- 'roles' => '',
+ protected array $testUserAccess = [
+ 'permissions' => 'update-{{ modelKebabCase }}',
+ 'roles' => '',
];
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_update_{{ modelSnake }}(): void
+ public function test_update_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
- ${{ modelEntity }} = {{ model }}::factory()->create();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
$data = $this->getTestData();
$expectedData = array_merge($data, [
- 'id' => ${{ modelEntity }}->getKey(),
+ 'id' => ${{ modelCamelCase }}->getKey(),
]);
- $this->patchJson(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]), $data)
+ $this->patchJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]), $data)
->assertOk()
->assertJson(fn (AssertableJson $json) =>
$json->has('data', fn (AssertableJson $json) =>
@@ -47,28 +43,58 @@ class {{ class }} extends TestCase
)
);
- $this->assertExistsModelWhereColumns({{ model }}::class, $expectedData);
+ $this->assertDatabaseHas({{ model }}::class, $expectedData);
+ }
+
+ public function test_update_{{ modelSnakeCase }}_with_invalid_data(): void
+ {
+ $this->actingAsTestUser();
+
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
+
+ $this->patchJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]), [])
+ ->assertUnprocessable()
+ ->assertJsonValidationErrors([
+ // TODO: add expected validation errors here
+ ]);
+ }
+
+ public function test_update_{{ modelSnakeCase }}_unauthenticated(): void
+ {
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
+
+ $data = $this->getTestData();
+
+ $this->patchJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]), $data)
+ ->assertUnauthorized();
}
- public function test_update_{{ modelSnake }}_without_access(): void
+ public function test_update_{{ modelSnakeCase }}_without_access(): void
{
- $this->getTestingUserWithoutAccess();
+ $this->actingAsTestUserWithoutAccess();
- ${{ modelEntity }} = {{ model }}::factory()->create();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
$data = $this->getTestData();
- $this->patchJson(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]), $data)
+ $this->patchJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]), $data)
->assertForbidden();
}
- public function test_update_non_existing_{{ modelSnake }}(): void
+ public function test_update_non_existing_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
$data = $this->getTestData();
- $this->patchJson(route('{{ routeName }}', ['{{ modelEntity }}' => 7777]), $data)
+ $this->patchJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => 7777]), $data)
->assertNotFound();
}
+
+ protected function getTestData(array $mergeData = []): array
+ {
+ return array_merge([
+ // TODO: add fields here
+ ], $mergeData);
+ }
}
diff --git a/src/Commands/Generators/stubs/test/api/view.stub b/src/Commands/Generators/stubs/test/api/view.stub
index a8b530c..61e3b16 100644
--- a/src/Commands/Generators/stubs/test/api/view.stub
+++ b/src/Commands/Generators/stubs/test/api/view.stub
@@ -2,32 +2,35 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
-use Illuminate\Testing\Fluent\AssertableJson;
use {{ modelNamespace }}\{{ model }};
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Testing\Fluent\AssertableJson;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group api
*/
class {{ class }} extends TestCase
{
+ use RefreshDatabase;
+
/**
* Roles and permissions, to be attached on the user by default
*/
- protected array $access = [
- 'permissions' => 'view-{{ modelPermissionEntity }}',
- 'roles' => '',
+ protected array $testUserAccess = [
+ 'permissions' => 'view-{{ modelKebabCase }}',
+ 'roles' => '',
];
- public function test_view_{{ modelSnake }}(): void
+ public function test_view_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
- ${{ modelEntity }} = {{ model }}::factory()->create();
- $expectedData = ${{ modelEntity }}->toArray();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
+ $expectedData = ${{ modelCamelCase }}->toArray();
- $this->getJson(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]))
+ $this->getJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]))
->assertOk()
->assertJson(fn (AssertableJson $json) =>
$json->has('data', fn (AssertableJson $json) =>
@@ -37,21 +40,29 @@ class {{ class }} extends TestCase
);
}
- public function test_view_{{ modelSnake }}_without_access(): void
+ public function test_view_{{ modelSnakeCase }}_unauthenticated(): void
+ {
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
+
+ $this->getJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]))
+ ->assertUnauthorized();
+ }
+
+ public function test_view_{{ modelSnakeCase }}_without_access(): void
{
- $this->getTestingUserWithoutAccess();
+ $this->actingAsTestUserWithoutAccess();
- ${{ modelEntity }} = {{ model }}::factory()->create();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
- $this->getJson(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]))
+ $this->getJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]))
->assertForbidden();
}
- public function test_view_not_existing_{{ modelSnake }}(): void
+ public function test_view_not_existing_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
- $this->getJson(route('{{ routeName }}', ['{{ modelEntity }}' => 7777]))
+ $this->getJson(route('{{ routeName }}', ['{{ modelCamelCase }}' => 7777]))
->assertNotFound();
}
}
diff --git a/src/Commands/Generators/stubs/test/cli/plain.stub b/src/Commands/Generators/stubs/test/cli/plain.stub
index 38602c3..39003c4 100644
--- a/src/Commands/Generators/stubs/test/cli/plain.stub
+++ b/src/Commands/Generators/stubs/test/cli/plain.stub
@@ -2,10 +2,10 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group cli
*/
class {{ class }} extends TestCase
diff --git a/src/Commands/Generators/stubs/test/feature/plain.stub b/src/Commands/Generators/stubs/test/feature/plain.stub
index 2bca030..e975e05 100644
--- a/src/Commands/Generators/stubs/test/feature/plain.stub
+++ b/src/Commands/Generators/stubs/test/feature/plain.stub
@@ -2,10 +2,10 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group feature
*/
class {{ class }} extends TestCase
diff --git a/src/Commands/Generators/stubs/test/unit/plain.stub b/src/Commands/Generators/stubs/test/unit/plain.stub
index baa4038..3257440 100644
--- a/src/Commands/Generators/stubs/test/unit/plain.stub
+++ b/src/Commands/Generators/stubs/test/unit/plain.stub
@@ -2,10 +2,10 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group unit
*/
class {{ class }} extends TestCase
diff --git a/src/Commands/Generators/stubs/test/web/create.stub b/src/Commands/Generators/stubs/test/web/create.stub
index e59b1fa..c1c366e 100644
--- a/src/Commands/Generators/stubs/test/web/create.stub
+++ b/src/Commands/Generators/stubs/test/web/create.stub
@@ -2,11 +2,11 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
use {{ modelNamespace }}\{{ model }};
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group web
*/
class {{ class }} extends TestCase
@@ -14,9 +14,9 @@ class {{ class }} extends TestCase
/**
* Roles and permissions, to be attached on the user by default
*/
- protected array $access = [
- 'permissions' => 'create-{{ modelPermissionEntity }}',
- 'roles' => '',
+ protected array $testUserAccess = [
+ 'permissions' => 'create-{{ modelKebabCase }}',
+ 'roles' => '',
];
protected function getTestData(array $mergeData = []): array
@@ -26,21 +26,21 @@ class {{ class }} extends TestCase
], $mergeData);
}
- public function test_create_{{ modelSnake }}(): void
+ public function test_create_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
$data = $this->getTestData();
$this->post(route('{{ routeName }}'), $data)
->assertCreated();
- $this->assertExistsModelWhereColumns({{ model }}::class, $data);
+ $this->assertDatabaseHas({{ model }}::class, $data);
}
- public function test_create_{{ modelSnake }}_without_access(): void
+ public function test_create_{{ modelSnakeCase }}_without_access(): void
{
- $this->getTestingUserWithoutAccess();
+ $this->actingAsTestUserWithoutAccess();
$data = $this->getTestData();
diff --git a/src/Commands/Generators/stubs/test/web/delete.stub b/src/Commands/Generators/stubs/test/web/delete.stub
index ee46de7..9fbf460 100644
--- a/src/Commands/Generators/stubs/test/web/delete.stub
+++ b/src/Commands/Generators/stubs/test/web/delete.stub
@@ -2,11 +2,11 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
use {{ modelNamespace }}\{{ model }};
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group web
*/
class {{ class }} extends TestCase
@@ -14,38 +14,38 @@ class {{ class }} extends TestCase
/**
* Roles and permissions, to be attached on the user by default
*/
- protected array $access = [
- 'permissions' => 'delete-{{ modelPermissionEntity }}',
- 'roles' => '',
+ protected array $testUserAccess = [
+ 'permissions' => 'delete-{{ modelKebabCase }}',
+ 'roles' => '',
];
- public function test_delete_{{ modelSnake }}(): void
+ public function test_delete_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
- ${{ modelEntity }} = {{ model }}::factory()->create();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
- $this->delete(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]))
+ $this->delete(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]))
->assertNoContent();
- $this->assertNull({{ model }}::find(${{ modelEntity }}->getKey()));
+ $this->assertNull({{ model }}::find(${{ modelCamelCase }}->getKey()));
}
- public function test_delete_{{ modelSnake }}_without_access(): void
+ public function test_delete_{{ modelSnakeCase }}_without_access(): void
{
- $this->getTestingUserWithoutAccess();
+ $this->actingAsTestUserWithoutAccess();
- ${{ modelEntity }} = {{ model }}::factory()->create();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
- $this->delete(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]))
+ $this->delete(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]))
->assertForbidden();
}
- public function test_delete_not_existing_{{ modelSnake }}(): void
+ public function test_delete_not_existing_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
- $this->delete(route('{{ routeName }}', ['{{ modelEntity }}' => 7777]))
+ $this->delete(route('{{ routeName }}', ['{{ modelCamelCase }}' => 7777]))
->assertNotFound();
}
}
diff --git a/src/Commands/Generators/stubs/test/web/plain.stub b/src/Commands/Generators/stubs/test/web/plain.stub
index 646711c..ac802d5 100644
--- a/src/Commands/Generators/stubs/test/web/plain.stub
+++ b/src/Commands/Generators/stubs/test/web/plain.stub
@@ -2,10 +2,10 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group web
*/
class {{ class }} extends TestCase
diff --git a/src/Commands/Generators/stubs/test/web/update.stub b/src/Commands/Generators/stubs/test/web/update.stub
index 64a67f9..82c1cd0 100644
--- a/src/Commands/Generators/stubs/test/web/update.stub
+++ b/src/Commands/Generators/stubs/test/web/update.stub
@@ -2,11 +2,11 @@
namespace {{ namespace }};
-use App\Ship\Abstracts\Tests\TestCase;
use {{ modelNamespace }}\{{ model }};
+use Tests\TestCase;
/**
- * @group {{ moduleKey }}
+ * @group {{ group }}
* @group web
*/
class {{ class }} extends TestCase
@@ -14,9 +14,9 @@ class {{ class }} extends TestCase
/**
* Roles and permissions, to be attached on the user by default
*/
- protected array $access = [
- 'permissions' => 'update-{{ modelPermissionEntity }}',
- 'roles' => '',
+ protected array $testUserAccess = [
+ 'permissions' => 'update-{{ modelKebabCase }}',
+ 'roles' => '',
];
protected function getTestData(array $mergeData = []): array
@@ -26,42 +26,42 @@ class {{ class }} extends TestCase
], $mergeData);
}
- public function test_update_{{ modelSnake }}(): void
+ public function test_update_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
- ${{ modelEntity }} = {{ model }}::factory()->create();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
$data = $this->getTestData();
$expectedData = array_merge($data, [
- 'id' => ${{ modelEntity }}->getKey(),
+ 'id' => ${{ modelCamelCase }}->getKey(),
]);
- $this->patch(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]), $data)
+ $this->patch(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]), $data)
->assertOk();
- $this->assertExistsModelWhereColumns({{ model }}::class, $expectedData);
+ $this->assertDatabaseHas({{ model }}::class, $expectedData);
}
- public function test_update_{{ modelSnake }}WithoutAccess(): void
+ public function test_update_{{ modelSnakeCase }}_without_access(): void
{
- $this->getTestingUserWithoutAccess();
+ $this->actingAsTestUserWithoutAccess();
- ${{ modelEntity }} = {{ model }}::factory()->create();
+ ${{ modelCamelCase }} = {{ model }}::factory()->create();
$data = $this->getTestData();
- $this->patch(route('{{ routeName }}', ['{{ modelEntity }}' => ${{ modelEntity }}->getKey()]), $data)
+ $this->patch(route('{{ routeName }}', ['{{ modelCamelCase }}' => ${{ modelCamelCase }}->getKey()]), $data)
->assertForbidden();
}
- public function test_update_non_existing_{{ modelSnake }}(): void
+ public function test_update_non_existing_{{ modelSnakeCase }}(): void
{
- $this->getTestingUser();
+ $this->actingAsTestUser();
$data = $this->getTestData();
- $this->patch(route('{{ routeName }}', ['{{ modelEntity }}' => 7777]), $data)
+ $this->patch(route('{{ routeName }}', ['{{ modelCamelCase }}' => 7777]), $data)
->assertNotFound();
}
}
diff --git a/src/Commands/InstallCommand.php b/src/Commands/InstallCommand.php
deleted file mode 100755
index fcae1e7..0000000
--- a/src/Commands/InstallCommand.php
+++ /dev/null
@@ -1,148 +0,0 @@
-argument('name'))) {
- return $this->installFromFile();
- }
-
- $this->install(
- $this->argument('name'),
- $this->argument('version'),
- $this->option('type'),
- $this->option('tree')
- );
-
- return self::SUCCESS;
- }
-
- /**
- * 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 self::FAILURE;
- }
-
- $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 self::SUCCESS;
- }
-
- /**
- * 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(): array
- {
- 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(): array
- {
- 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],
- ];
- }
-}
diff --git a/src/Commands/ListCommand.php b/src/Commands/ListCommand.php
old mode 100755
new mode 100644
index 7efa401..67eb3ab
--- a/src/Commands/ListCommand.php
+++ b/src/Commands/ListCommand.php
@@ -2,19 +2,16 @@
namespace Laraneat\Modules\Commands;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Facades\Modules;
use Laraneat\Modules\Module;
-use Symfony\Component\Console\Input\InputOption;
-class ListCommand extends Command
+class ListCommand extends BaseCommand
{
/**
- * The console command name.
+ * The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:list';
+ protected $signature = 'module:list';
/**
* The console command description.
@@ -28,62 +25,14 @@ class ListCommand extends Command
*/
public function handle(): int
{
- $this->table(['Name', 'Status', 'Priority', 'Path'], $this->getRows());
+ $this->table(
+ ['Package Name', 'Namespace', 'Path'],
+ collect($this->modulesRepository->getModules())
+ ->map(fn (Module $module) => [$module->getPackageName(), $module->getNamespace(), $module->getPath()])
+ ->values()
+ ->toArray()
+ );
return self::SUCCESS;
}
-
- /**
- * Get table rows.
- *
- * @return array
- */
- public function getRows(): array
- {
- $rows = [];
-
- foreach ($this->getModules() as $module) {
- $rows[] = [
- $module->getName(),
- $module->isEnabled() ? 'Enabled' : 'Disabled',
- $module->get('priority'),
- $module->getPath(),
- ];
- }
-
- return $rows;
- }
-
- /**
- * @return Module[]
- */
- public function getModules(): array
- {
- switch ($this->option('only')) {
- case 'enabled':
- return Modules::getByStatus(true);
-
- case 'disabled':
- return Modules::getByStatus(false);
-
- case 'priority':
- return Modules::getOrdered($this->option('direction'));
-
- default:
- return Modules::all();
- }
- }
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
- {
- return [
- ['only', 'o', InputOption::VALUE_OPTIONAL, 'Types of modules will be displayed.', null],
- ['direction', 'd', InputOption::VALUE_OPTIONAL, 'The direction of ordering.', 'asc'],
- ];
- }
}
diff --git a/src/Commands/MigrateCommand.php b/src/Commands/MigrateCommand.php
old mode 100755
new mode 100644
index dd6e488..d6ad43e
--- a/src/Commands/MigrateCommand.php
+++ b/src/Commands/MigrateCommand.php
@@ -2,106 +2,54 @@
namespace Laraneat\Modules\Commands;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Facades\Modules;
-use Laraneat\Modules\Migrations\Migrator;
use Laraneat\Modules\Module;
-use Symfony\Component\Console\Input\InputArgument;
-use Symfony\Component\Console\Input\InputOption;
-class MigrateCommand extends Command
+class MigrateCommand extends BaseMigrationCommand
{
/**
- * The console command name.
+ * The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:migrate';
+ protected $signature = 'module:migrate
+ {module?* : Module name(s) or package name(s)}
+ {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}
+ {--database= : The database connection to use}
+ {--force : Force the operation to run when in production}
+ {--schema-path= : The path to a schema dump file}
+ {--pretend : Dump the SQL queries that would be run}
+ {--seed : Indicates if the seed task should be re-run}
+ {--seeder= : The class name of the root seeder}
+ {--step : Force the migrations to be run so they can be rolled back individually}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Migrate the migrations from the specified module or from all modules.';
-
- /**
- * Execute the console command.
- *
- * @return int
- */
- public function handle(): int
- {
- $name = $this->argument('module');
-
- if ($name) {
- $module = Modules::findOrFail($name);
-
- $this->migrate($module);
-
- return self::SUCCESS;
- }
-
- foreach (Modules::getOrdered($this->option('direction')) as $module) {
- $this->line('Running for module: ' . $module->getName() . '');
-
- $this->migrate($module);
- }
-
- return self::SUCCESS;
- }
+ protected $description = 'Migrate the migrations from the specified module(s) or from all modules.';
/**
* Run the migration from the specified module.
- *
- * @param Module $module
*/
- protected function migrate(Module $module)
+ protected function executeForModule(Module $module): void
{
- $path = str_replace(base_path(), '', (new Migrator($module, $this->getLaravel()))->getPath());
-
- if ($this->option('subpath')) {
- $path .= "/" . $this->option("subpath");
- }
-
$this->call('migrate', [
- '--path' => $path,
+ '--path' => $this->getMigrationPaths($module),
+ '--realpath' => (bool) $this->option('realpath'),
'--database' => $this->option('database'),
- '--pretend' => $this->option('pretend'),
- '--force' => $this->option('force'),
+ '--schema-path' => $this->option('schema-path'),
+ '--pretend' => (bool) $this->option('pretend'),
+ '--step' => (bool) $this->option('step'),
+ '--force' => true,
]);
- if ($this->option('seed')) {
- $this->call('module:seed', ['module' => $module->getName(), '--force' => $this->option('force')]);
+ if ($this->option('seed') && ! $this->option('pretend')) {
+ $this->call('module:seed', [
+ 'module' => $module->getName(),
+ '--class' => $this->option('seeder'),
+ '--force' => true,
+ ]);
}
}
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
- ];
- }
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
- {
- 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'],
- ];
- }
}
diff --git a/src/Commands/MigrateRefreshCommand.php b/src/Commands/MigrateRefreshCommand.php
old mode 100755
new mode 100644
index e26f67b..8ce4c2b
--- a/src/Commands/MigrateRefreshCommand.php
+++ b/src/Commands/MigrateRefreshCommand.php
@@ -2,22 +2,27 @@
namespace Laraneat\Modules\Commands;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Traits\ConsoleHelpersTrait;
-use Laraneat\Modules\Traits\ModuleCommandTrait;
-use Symfony\Component\Console\Input\InputArgument;
-use Symfony\Component\Console\Input\InputOption;
+use Illuminate\Console\ConfirmableTrait;
-class MigrateRefreshCommand extends Command
+class MigrateRefreshCommand extends BaseCommand
{
- use ConsoleHelpersTrait, ModuleCommandTrait;
+ use ConfirmableTrait;
/**
- * The console command name.
+ * The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:migrate-refresh';
+ protected $signature = 'module:migrate:refresh
+ {module?* : Module name(s) or package name(s)}
+ {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}
+ {--database= : The database connection to use}
+ {--force : Force the operation to run when in production}
+ {--schema-path= : The path to a schema dump file}
+ {--pretend : Dump the SQL queries that would be run}
+ {--seed : Indicates if the seed task should be re-run}
+ {--seeder= : The class name of the root seeder}
+ {--step : Force the migrations to be run so they can be rolled back individually}';
/**
* The console command description.
@@ -31,52 +36,30 @@ class MigrateRefreshCommand extends Command
*/
public function handle(): int
{
- $module = $this->getModule();
+ if (! $this->confirmToProceed()) {
+ return self::FAILURE;
+ }
- $this->call('module:migrate-reset', [
- 'module' => $module->getStudlyName(),
+ $this->call('module:migrate:reset', [
+ 'module' => $this->argument('module'),
+ '--realpath' => $this->option('realpath'),
'--database' => $this->option('database'),
- '--force' => $this->option('force'),
+ '--pretend' => $this->option('pretend'),
+ '--force' => true,
]);
$this->call('module:migrate', [
- 'module' => $module->getStudlyName(),
+ 'module' => $this->argument('module'),
+ '--realpath' => $this->option('realpath'),
'--database' => $this->option('database'),
- '--force' => $this->option('force'),
+ '--schema-path' => $this->option('schema-path'),
+ '--pretend' => $this->option('pretend'),
+ '--seed' => $this->option('seed'),
+ '--seeder' => $this->option('seeder'),
+ '--step' => $this->option('step'),
+ '--force' => true,
]);
- if ($this->option('seed')) {
- $this->call('module:seed', [
- 'module' => $module->getStudlyName(),
- ]);
- }
-
return self::SUCCESS;
}
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
- ];
- }
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
- {
- 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.'],
- ];
- }
}
diff --git a/src/Commands/MigrateResetCommand.php b/src/Commands/MigrateResetCommand.php
old mode 100755
new mode 100644
index af5da76..248e9dc
--- a/src/Commands/MigrateResetCommand.php
+++ b/src/Commands/MigrateResetCommand.php
@@ -2,22 +2,21 @@
namespace Laraneat\Modules\Commands;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Contracts\RepositoryInterface;
-use Laraneat\Modules\Facades\Modules;
-use Laraneat\Modules\Migrations\Migrator;
use Laraneat\Modules\Module;
-use Symfony\Component\Console\Input\InputArgument;
-use Symfony\Component\Console\Input\InputOption;
-class MigrateResetCommand extends Command
+class MigrateResetCommand extends BaseMigrationCommand
{
/**
- * The console command name.
+ * The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:migrate-reset';
+ protected $signature = 'module:migrate:reset
+ {module?* : Module name(s) or package name(s)}
+ {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}
+ {--database= : The database connection to use}
+ {--force : Force the operation to run when in production}
+ {--pretend : Dump the SQL queries that would be run}';
/**
* The console command description.
@@ -27,88 +26,16 @@ class MigrateResetCommand extends Command
protected $description = 'Reset the modules migrations.';
/**
- * @var RepositoryInterface
+ * Reset migration from the specified module.
*/
- protected RepositoryInterface $repository;
-
- /**
- * Execute the console command.
- */
- public function handle(): int
- {
- $name = $this->argument('module');
-
- if (!empty($name)) {
- $this->reset($name);
-
- return self::SUCCESS;
- }
-
- foreach (Modules::getOrdered($this->option('direction')) as $module) {
- $this->line('Running for module: ' . $module->getName() . '');
-
- $this->reset($module);
- }
-
- return self::SUCCESS;
- }
-
- /**
- * Rollback migration from the specified module.
- *
- * @param Module|string $module
- */
- public function reset($module): void
- {
- if (is_string($module)) {
- $module = Modules::findOrFail($module);
- }
-
- $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: {$migration}");
- }
-
- return;
- }
-
- $this->comment('Nothing to rollback.');
- }
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
- ];
- }
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
+ protected function executeForModule(Module $module): void
{
- 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.'],
- ];
+ $this->call('migrate:reset', [
+ '--path' => $this->getMigrationPaths($module),
+ '--database' => $this->option('database'),
+ '--realpath' => (bool) $this->option('realpath'),
+ '--pretend' => (bool) $this->option('pretend'),
+ '--force' => true,
+ ]);
}
}
diff --git a/src/Commands/MigrateRollbackCommand.php b/src/Commands/MigrateRollbackCommand.php
old mode 100755
new mode 100644
index 6ef86d1..f3f6499
--- a/src/Commands/MigrateRollbackCommand.php
+++ b/src/Commands/MigrateRollbackCommand.php
@@ -2,21 +2,23 @@
namespace Laraneat\Modules\Commands;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Facades\Modules;
-use Laraneat\Modules\Migrations\Migrator;
use Laraneat\Modules\Module;
-use Symfony\Component\Console\Input\InputArgument;
-use Symfony\Component\Console\Input\InputOption;
-class MigrateRollbackCommand extends Command
+class MigrateRollbackCommand extends BaseMigrationCommand
{
/**
- * The console command name.
+ * The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:migrate-rollback';
+ protected $signature = 'module:migrate:rollback
+ {module?* : Module name(s) or package name(s)}
+ {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}
+ {--database= : The database connection to use}
+ {--force : Force the operation to run when in production}
+ {--pretend : Dump the SQL queries that would be run}
+ {--step= : The number of migrations to be reverted}
+ {--batch= : The batch of migrations (identified by their batch number) to be reverted}';
/**
* The console command description.
@@ -25,84 +27,19 @@ class MigrateRollbackCommand extends Command
*/
protected $description = 'Rollback the modules migrations.';
- /**
- * Execute the console command.
- */
- public function handle(): int
- {
- $name = $this->argument('module');
-
- if (!empty($name)) {
- $this->rollback($name);
-
- return self::SUCCESS;
- }
-
- foreach (Modules::getOrdered($this->option('direction')) as $module) {
- $this->line('Running for module: ' . $module->getName() . '');
-
- $this->rollback($module);
- }
-
- return self::SUCCESS;
- }
-
/**
* Rollback migration from the specified module.
- *
- * @param Module|string $module
- */
- public function rollback($module): void
- {
- if (is_string($module)) {
- $module = Modules::findOrFail($module);
- }
-
- $migrator = new Migrator($module, $this->getLaravel());
-
- $database = $this->option('database');
-
- if (!empty($database)) {
- $migrator->setDatabase($database);
- }
-
- $migrated = $migrator->rollback();
-
- if (count($migrated)) {
- foreach ($migrated as $migration) {
- $this->line("Rollback: {$migration}");
- }
-
- return;
- }
-
- $this->comment('Nothing to rollback.');
- }
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
- ];
- }
-
- /**
- * Get the console command options.
- *
- * @return array
*/
- protected function getOptions(): array
+ protected function executeForModule(Module $module): void
{
- 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.'],
- ];
+ $this->call('migrate:rollback', [
+ '--path' => $this->getMigrationPaths($module),
+ '--database' => $this->option('database'),
+ '--step' => $this->option('step') ?: null,
+ '--batch' => $this->option('batch') ?: null,
+ '--realpath' => (bool) $this->option('realpath'),
+ '--pretend' => (bool) $this->option('pretend'),
+ '--force' => true,
+ ]);
}
}
diff --git a/src/Commands/MigrateStatusCommand.php b/src/Commands/MigrateStatusCommand.php
old mode 100755
new mode 100644
index 2af5c8a..1af1b41
--- a/src/Commands/MigrateStatusCommand.php
+++ b/src/Commands/MigrateStatusCommand.php
@@ -2,91 +2,43 @@
namespace Laraneat\Modules\Commands;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Facades\Modules;
-use Laraneat\Modules\Migrations\Migrator;
use Laraneat\Modules\Module;
-use Symfony\Component\Console\Input\InputArgument;
-use Symfony\Component\Console\Input\InputOption;
-class MigrateStatusCommand extends Command
+class MigrateStatusCommand extends BaseMigrationCommand
{
/**
- * The console command name.
+ * The name and signature of the console command.
*
* @var string
*/
- protected $name = 'module:migrate-status';
+ protected $signature = 'module:migrate:status
+ {module?* : Module name(s) or package name(s)}
+ {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}
+ {--database= : The database connection to use}
+ {--pending : Only list pending migrations}';
/**
* The console command description.
*
* @var string
*/
- protected $description = 'Status for all module migrations';
+ protected $description = 'Show the status of the modules migrations.';
/**
- * Execute the console command.
- *
- * @return int
+ * Whether to require confirmation in production.
*/
- public function handle(): int
- {
- $name = $this->argument('module');
-
- if ($name) {
- $module = Modules::findOrFail($name);
-
- $this->migrateStatus($module);
-
- return self::SUCCESS;
- }
-
- foreach (Modules::getOrdered($this->option('direction')) as $module) {
- $this->line('Running for module: ' . $module->getName() . '');
- $this->migrateStatus($module);
- }
-
- return self::SUCCESS;
- }
+ protected bool $requiresConfirmation = false;
/**
- * Run the migration from the specified module.
- *
- * @param Module $module
+ * Show migration status from the specified module.
*/
- protected function migrateStatus(Module $module): void
+ protected function executeForModule(Module $module): void
{
- $path = str_replace(base_path(), '', (new Migrator($module, $this->getLaravel()))->getPath());
-
$this->call('migrate:status', [
- '--path' => $path,
+ '--path' => $this->getMigrationPaths($module),
'--database' => $this->option('database'),
+ '--realpath' => (bool) $this->option('realpath'),
+ '--pending' => (bool) $this->option('pending'),
]);
}
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
- ];
- }
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
- {
- return [
- ['direction', 'd', InputOption::VALUE_OPTIONAL, 'The direction of ordering.', 'asc'],
- ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
- ];
- }
}
diff --git a/src/Commands/ModuleDeleteCommand.php b/src/Commands/ModuleDeleteCommand.php
old mode 100755
new mode 100644
index 63a7874..e0ae045
--- a/src/Commands/ModuleDeleteCommand.php
+++ b/src/Commands/ModuleDeleteCommand.php
@@ -2,28 +2,60 @@
namespace Laraneat\Modules\Commands;
-use Illuminate\Console\Command;
-use Laraneat\Modules\Facades\Modules;
-use Symfony\Component\Console\Input\InputArgument;
+use Illuminate\Console\ConfirmableTrait;
+use Laraneat\Modules\Exceptions\ComposerException;
+use Laraneat\Modules\Exceptions\ModuleHasNoNamespace;
+use Laraneat\Modules\Exceptions\ModuleHasNonUniquePackageName;
+use Laraneat\Modules\Exceptions\ModuleNotFound;
-class ModuleDeleteCommand extends Command
+class ModuleDeleteCommand extends BaseCommand
{
- protected $name = 'module:delete';
- protected $description = 'Remove a module from the application';
+ use ConfirmableTrait;
+
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'module:delete
+ {module?* : Module name(s) or package name(s) to delete}
+ {--force : Force the operation to run when in production}';
+
+ /**
+ * The console command description.
+ *
+ * @var string
+ */
+ protected $description = 'Delete the specified module(s)';
public function handle(): int
{
- Modules::delete($this->argument('module'));
+ if (! $this->confirmToProceed()) {
+ return self::FAILURE;
+ }
- $this->info("Module {$this->argument('module')} has been deleted.");
+ try {
+ $modulesToDelete = $this->getModuleArgumentOrFail();
+ } catch (ModuleNotFound|ModuleHasNonUniquePackageName|ModuleHasNoNamespace $exception) {
+ $this->error($exception->getMessage());
- return self::SUCCESS;
- }
+ return self::FAILURE;
+ }
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::REQUIRED, 'The name of module to delete.'],
- ];
+ foreach ($modulesToDelete as $moduleToDelete) {
+ try {
+ $status = $this->modulesRepository->delete($moduleToDelete->getPackageName(), $this->output);
+ if ($status) {
+ $this->components->info("Module [{$moduleToDelete->getPackageName()}] has been deleted.");
+ } else {
+ $this->components->error("Failed to remove module [{$moduleToDelete->getPackageName()}].");
+ }
+ } catch (ComposerException $exception) {
+ $this->components->error($exception->getMessage());
+ $this->components->info("Please run composer remove {$moduleToDelete->getPackageName()} manually");
+ }
+ }
+
+ return self::SUCCESS;
}
}
diff --git a/src/Commands/SeedCommand.php b/src/Commands/SeedCommand.php
deleted file mode 100755
index e2659c9..0000000
--- a/src/Commands/SeedCommand.php
+++ /dev/null
@@ -1,232 +0,0 @@
-argument('module')) {
- $name = Str::studly($name);
- $this->moduleSeed($this->getModuleByName($name));
- } else {
- $modules = Modules::getOrdered();
- array_walk($modules, [$this, 'moduleSeed']);
- $this->info('All modules seeded.');
- }
- } 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 self::FAILURE;
- } catch (\Exception $e) {
- $this->reportException($e);
- $this->renderException($this->getOutput(), $e);
-
- return self::FAILURE;
- }
-
- return self::SUCCESS;
- }
-
- /**
- * @param string $moduleName
- *
- * @throws RuntimeException
- *
- * @return Module
- */
- public function getModuleByName(string $moduleName): Module
- {
- if (!Modules::has($moduleName)) {
- throw new RuntimeException("Module [$moduleName] does not exists.");
- }
-
- return Modules::find($moduleName);
- }
-
- /**
- * @param Module $module
- *
- * @return void
- */
- public function moduleSeed(Module $module): void
- {
- $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
- 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(string $className): void
- {
- 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(string $name): string
- {
- $name = Str::studly($name);
-
- $namespace = Modules::config('namespace');
- $config = GeneratorHelper::component('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(string $name): array
- {
- $name = Str::studly($name);
-
- $seederPath = GeneratorHelper::component('seeder');
- $seederPath = str_replace('/', '\\', $seederPath->getPath());
-
- $foundModules = [];
- foreach (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 OutputInterface $output
- * @param \Exception $e
- * @return void
- */
- protected function renderException(OutputInterface $output, \Exception $e)
- {
- $this->laravel[ExceptionHandler::class]->renderForConsole($output, $e);
- }
-
- /**
- * Report the exception to the exception handler.
- *
- * @param \Exception $e
- * @return void
- */
- protected function reportException(\Exception $e)
- {
- $this->laravel[ExceptionHandler::class]->report($e);
- }
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'The name of module will be used.'],
- ];
- }
-
- /**
- * Get the console command options.
- *
- * @return array
- */
- protected function getOptions(): array
- {
- 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.'],
- ];
- }
-}
diff --git a/src/Commands/SetupCommand.php b/src/Commands/SetupCommand.php
deleted file mode 100755
index af45dbb..0000000
--- a/src/Commands/SetupCommand.php
+++ /dev/null
@@ -1,66 +0,0 @@
-generateModulesFolder();
- }
-
- /**
- * Generate the modules folder.
- */
- public function generateModulesFolder()
- {
- return $this->generateDirectory(
- Modules::config('paths.generators'),
- 'Modules directory created successfully',
- 'Modules 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->info($success);
-
- return self::SUCCESS;
- }
-
- $this->error($error);
-
- return self::FAILURE;
- }
-}
diff --git a/src/Commands/StubPublishCommand.php b/src/Commands/StubPublishCommand.php
new file mode 100644
index 0000000..37d6916
--- /dev/null
+++ b/src/Commands/StubPublishCommand.php
@@ -0,0 +1,54 @@
+ensureDirectoryExists($customStubsPath = GeneratorHelper::getCustomStubsPath());
+ $originalStubsPath = realpath(__DIR__ . '/Generators/stubs');
+
+ foreach ($filesystem->allFiles($originalStubsPath) as $file) {
+ $from = $file->getRealPath();
+ $relativePath = Str::after($file->getRealPath(), $originalStubsPath);
+ $to = $customStubsPath . '/' . ltrim($relativePath, '/');
+
+ $onlyExisting = $this->option('existing');
+ $force = $this->option('force');
+ $toIsExists = $filesystem->exists($to);
+
+ if (($onlyExisting && $toIsExists) || (! $onlyExisting && (! $toIsExists || $force))) {
+ $filesystem->ensureDirectoryExists(dirname($to));
+ $filesystem->put($to, $filesystem->get($from));
+ }
+ }
+
+ $this->components->info(sprintf('Stubs have been successfully published to the "%s" directory.', $customStubsPath));
+ }
+}
diff --git a/src/Commands/SyncCommand.php b/src/Commands/SyncCommand.php
new file mode 100644
index 0000000..a85d7dc
--- /dev/null
+++ b/src/Commands/SyncCommand.php
@@ -0,0 +1,45 @@
+modulesRepository->pruneModulesManifest();
+
+ try {
+ $this->modulesRepository->syncWithComposer($this->output);
+ $this->components->info("Modules completed successfully!");
+ } catch (ModuleHasNoNamespace|ModuleHasNonUniquePackageName $e) {
+ $this->components->error($e->getMessage());
+ } catch (ComposerException $e) {
+ $this->components->error($e->getMessage());
+ $modulePackageNames = join(" ", array_keys($this->modulesRepository->getModules()));
+ $this->components->info("Please run composer update {$modulePackageNames} manually");
+ }
+
+ return self::SUCCESS;
+ }
+}
diff --git a/src/Commands/UnUseCommand.php b/src/Commands/UnUseCommand.php
deleted file mode 100755
index 867e44b..0000000
--- a/src/Commands/UnUseCommand.php
+++ /dev/null
@@ -1,35 +0,0 @@
-info('Previous module used successfully forgotten.');
-
- return self::SUCCESS;
- }
-}
diff --git a/src/Commands/UpdateCommand.php b/src/Commands/UpdateCommand.php
deleted file mode 100755
index 15b3c82..0000000
--- a/src/Commands/UpdateCommand.php
+++ /dev/null
@@ -1,68 +0,0 @@
-argument('module');
-
- if ($name) {
- $this->updateModule($name);
-
- return self::SUCCESS;
- }
-
- foreach (Modules::getOrdered() as $module) {
- $this->updateModule($module->getName());
- }
-
- return self::SUCCESS;
- }
-
- protected function updateModule(string $moduleName): void
- {
- $this->line('Running for module: ' . $moduleName . '');
-
- Modules::update($moduleName);
-
- $this->info("Module [{$moduleName}] updated successfully.");
- }
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::OPTIONAL, 'The name of module will be updated.'],
- ];
- }
-}
diff --git a/src/Commands/UseCommand.php b/src/Commands/UseCommand.php
deleted file mode 100755
index 2aa1e1d..0000000
--- a/src/Commands/UseCommand.php
+++ /dev/null
@@ -1,57 +0,0 @@
-argument('module'));
-
- if (!Modules::has($module)) {
- $this->error("Module [{$module}] does not exists.");
-
- return self::FAILURE;
- }
-
- Modules::setUsed($module);
-
- $this->info("Module [{$module}] used successfully.");
-
- return self::SUCCESS;
- }
-
- /**
- * Get the console command arguments.
- *
- * @return array
- */
- protected function getArguments(): array
- {
- return [
- ['module', InputArgument::REQUIRED, 'The name of module will be used.'],
- ];
- }
-}
diff --git a/src/Contracts/ActivatorInterface.php b/src/Contracts/ActivatorInterface.php
deleted file mode 100755
index 6138ca9..0000000
--- a/src/Contracts/ActivatorInterface.php
+++ /dev/null
@@ -1,43 +0,0 @@
-
- */
- public function all(): array;
-
- /**
- * Get cached modules.
- *
- * @return array
- */
- public function getCached(): array;
-
- /**
- * Scan & get all available modules.
- *
- * @return array
- */
- public function scan(): array;
-
- /**
- * Get modules as modules collection instance.
- *
- * @return Collection
- */
- public function toCollection(): Collection;
-
- /**
- * Get scanned paths.
- *
- * @return string[]
- */
- public function getScanPaths(): array;
-
- /**
- * Get list of enabled modules.
- *
- * @return array
- */
- public function allEnabled(): array;
-
- /**
- * Get list of disabled modules.
- *
- * @return array
- */
- public function allDisabled(): array;
-
- /**
- * Get count from all modules.
- */
- public function count(): int;
-
- /**
- * Get all ordered modules.
- *
- * @param string $direction
- *
- * @return array
- */
- public function getOrdered(string $direction = 'asc'): array;
-
- /**
- * Get modules by the given status.
- *
- * @param bool $status
- *
- * @return array
- */
- public function getByStatus(bool $status): array;
-
- /**
- * Find a specific module.
- */
- public function find(string $moduleName): ?Module;
-
- /**
- * Find all modules that are required by a module. If the module cannot be found, throw an exception.
- *
- * @param string $moduleName
- *
- * @return array
- * @throws ModuleNotFoundException
- */
- public function findRequirements(string $moduleName): array;
-
- /**
- * Find a specific module. If there return that, otherwise throw exception.
- *
- * @throws ModuleNotFoundException
- */
- public function findOrFail(string $moduleName): Module;
-
- /**
- * Get path for a specific module.
- */
- public function getModulePath(Module|string $module, ?string $extraPath = null): string;
-
- /**
- * Get namespace for a specific module.
- */
- public function getModuleNamespace(Module|string $module, ?string $extraNamespace = null): string;
-
- public function getFilesystem(): Filesystem;
-
- /**
- * Get a specific config data from a configuration file.
- */
- public function config(string $key, $default = null);
-
- /**
- * Get default modules path.
- */
- public function getDefaultPath(): string;
-
- /**
- * Find a specific module by its alias.
- */
- public function findByAlias(string $alias): ?Module;
-
- /**
- * Boot the modules.
- */
- public function boot(): void;
-
- /**
- * Register the modules.
- */
- public function register(): void;
-
- /**
- * Get asset path for a specific module.
- */
- public function assetPath(string $moduleName): string;
-
- /**
- * Delete a specific module.
- *
- * @throws ModuleNotFoundException
- */
- public function delete(string $moduleName): bool;
-
- /**
- * Determine whether the given module is activated.
- *
- * @throws ModuleNotFoundException
- */
- public function isEnabled(string $moduleName): bool;
-
- /**
- * Determine whether the given module is not activated.
- *
- * @throws ModuleNotFoundException
- */
- public function isDisabled(string $moduleName): bool;
-}
diff --git a/src/Contracts/RunnableInterface.php b/src/Contracts/RunnableInterface.php
deleted file mode 100755
index f7d6927..0000000
--- a/src/Contracts/RunnableInterface.php
+++ /dev/null
@@ -1,11 +0,0 @@
-app = $app;
- $this->defaultPath = $defaultPath ? rtrim($defaultPath, '/') : null;
- $this->url = $app['url'];
- $this->config = $app['config'];
- $this->filesystem = $app['files'];
- $this->activator = $app[ActivatorInterface::class];
- $this->cache = $app['cache'];
- }
-
- /**
- * Register the modules.
- */
- public function register(): void
- {
- foreach ($this->getOrdered() as $module) {
- $module->register();
- }
- }
-
- /**
- * @inheritDoc
- * @see RepositoryInterface::boot()
- */
- public function boot(): void
- {
- foreach ($this->getOrdered() as $module) {
- $module->boot();
- }
- }
-
- /**
- * Get modules path.
- */
- public function getDefaultPath(): string
- {
- return $this->defaultPath ?: rtrim($this->config('generator.path', base_path('app/Modules')), '/');
- }
-
- /**
- * Get all additional paths.
- *
- * @return string[]
- */
- public function getPaths(): array
- {
- return $this->paths;
- }
-
- /**
- * Add other module location.
- */
- public function addLocation(string $path): static
- {
- $this->paths[] = $path;
- $this->flushCache();
-
- return $this;
- }
-
- /**
- * Get scanned modules paths.
- *
- * @return string[]
- */
- public function getScanPaths(): array
- {
- $paths = $this->paths;
-
- $paths[] = $this->getDefaultPath();
-
- if ($this->config('scan.enabled')) {
- $paths = array_merge($paths, $this->config('scan.paths'));
- }
-
- return array_map(static function ($path) {
- return Str::endsWith($path, '/*') ? $path : Str::finish($path, '/*');
- }, $paths);
- }
-
- /**
- * Get a module key by its name
- */
- public function getModuleKey(Module|string $module): string
- {
- return $module instanceof Module
- ? $module->getKey()
- : Str::snake($module, '-');
- }
-
- /**
- * Get path for a specific module.
- *
- * @throws ModuleNotFoundException
- */
- public function getModulePath(Module|string $module, ?string $extraPath = null): string
- {
- $modulePath = $module instanceof Module
- ? $module->getPath()
- : $this->findOrFail($module)->getPath();
-
- return $extraPath ? $modulePath . '/' . $extraPath : $modulePath;
- }
-
- /**
- * Get namespace for a specific module.
- *
- * @throws ModuleNotFoundException
- */
- public function getModuleNamespace(Module|string $module, ?string $extraNamespace = null): string
- {
- $moduleNamespace = $module instanceof Module
- ? $module->getNamespace()
- : $this->findOrFail($module)->getNamespace();
-
- return $extraNamespace ? $moduleNamespace . '\\' . $extraNamespace : $moduleNamespace;
- }
-
- /**
- * Get all modules.
- *
- * @return array
- */
- public function all(): array
- {
- if (is_array($this->cachedModules)) {
- return $this->cachedModules;
- }
-
- if (!$this->config('cache.enabled')) {
- return $this->cachedModules = $this->scan();
- }
-
- return $this->cachedModules = $this->getCached();
- }
-
- /**
- * Get list of enabled modules.
- *
- * @return array
- */
- public function allEnabled(): array
- {
- return $this->getByStatus(true);
- }
-
- /**
- * Get list of disabled modules.
- *
- * @return array
- */
- public function allDisabled(): array
- {
- return $this->getByStatus(false);
- }
-
- /**
- * Get cached modules.
- *
- * @return array
- */
- public function getCached(): array
- {
- return $this->formatCached($this->getRawCached());
- }
-
- /**
- * Get raw cache of modules.
- */
- protected function getRawCached(): array
- {
- return $this->cache->remember($this->config('cache.key'), $this->config('cache.lifetime'), function () {
- return $this->toCollection()->toArray();
- });
- }
-
- /**
- * Get all ordered modules.
- *
- * @return array
- */
- public function getOrdered(string $direction = 'asc'): array
- {
- $modules = $this->allEnabled();
-
- uasort($modules, static function (Module $a, Module $b) use ($direction) {
- if ($a->getPriority() === $b->getPriority()) {
- return 0;
- }
-
- if ($direction === 'desc') {
- return $a->getPriority() < $b->getPriority() ? 1 : -1;
- }
-
- return $a->getPriority() > $b->getPriority() ? 1 : -1;
- });
-
- return $modules;
- }
-
- /**
- * Get modules by status.
- *
- * @return array
- */
- public function getByStatus(bool $status): array
- {
- $modules = [];
-
- foreach ($this->all() as $moduleKey => $module) {
- if ($module->isStatus($status)) {
- $modules[$moduleKey] = $module;
- }
- }
-
- return $modules;
- }
-
- /**
- * Get & scan all modules.
- *
- * @return array
- */
- public function scan(): array
- {
- $paths = $this->getScanPaths();
-
- $modules = [];
-
- foreach ($paths as $path) {
- $manifests = $this->getFilesystem()->glob("$path/module.json");
-
- is_array($manifests) || $manifests = [];
-
- foreach ($manifests as $manifest) {
- $json = Json::make($manifest, $this->filesystem);
- $path = dirname($manifest);
- $name = (string) $json->get('name');
- $moduleKey = $this->getModuleKey($name);
- $namespace = (string) $json->get('namespace', '');
-
- $modules[$moduleKey] = $this->createModule(
- $this->app,
- $name,
- $path,
- $namespace,
- ['module.json' => $json]
- );
- }
- }
-
- return $modules;
- }
-
- /**
- * Creates a new Module instance
- */
- protected function createModule(
- Application $app,
- string $name,
- string $path,
- string $namespace,
- array $moduleJson = []
- ): Module {
- return new Module($app, $name, $path, $namespace, $moduleJson);
- }
-
- /**
- * Get all modules as collection instance.
- *
- * @return Collection
- */
- public function toCollection(): Collection
- {
- return new Collection($this->scan());
- }
-
- /**
- * Determine whether the given module exist.
- */
- public function has(string $moduleName): bool
- {
- $moduleKey = $this->getModuleKey($moduleName);
- return array_key_exists($moduleKey, $this->all());
- }
-
- /**
- * Get count from all modules.
- */
- public function count(): int
- {
- return count($this->all());
- }
-
- /**
- * Find a specific module.
- */
- public function find(string $moduleName): ?Module
- {
- $allModules = $this->all();
- $moduleKey = $this->getModuleKey($moduleName);
-
- return $allModules[$moduleKey] ?? null;
- }
-
- /**
- * Find a specific module by its alias.
- */
- public function findByAlias(string $alias): ?Module
- {
- foreach ($this->all() as $module) {
- if ($module->getAlias() === $alias) {
- return $module;
- }
- }
-
- return null;
- }
-
- /**
- * Find a specific module, if there return that, otherwise throw exception.
- *
- * @throws ModuleNotFoundException
- */
- public function findOrFail(string $moduleName): Module
- {
- $module = $this->find($moduleName);
-
- if ($module !== null) {
- return $module;
- }
-
- throw new ModuleNotFoundException("Module [$moduleName] does not exist!");
- }
-
- /**
- * Find all modules that are required by a module. If the module cannot be found, throw an exception.
- *
- * @return array
- * @throws ModuleNotFoundException
- */
- public function findRequirements(string $moduleName): array
- {
- $requirements = [];
-
- $module = $this->findOrFail($moduleName);
-
- foreach ($module->getRequires() as $requirementName) {
- $requirements[] = $this->findByAlias($requirementName);
- }
-
- return $requirements;
- }
-
- /**
- * Format the cached data as array of modules.
- *
- * @return array
- */
- protected function formatCached(array $cached): array
- {
- $modules = [];
-
- /**
- * @var string $moduleKey
- * @var array{name: string, path: string, namespace: string, module_json: array} $moduleArray
- */
- foreach ($cached as $moduleKey => $moduleArray) {
- $moduleJson = array_map(
- fn ($json) => Json::make($json['path'], $this->filesystem, $json['attributes']),
- $moduleArray['module_json'] ?? []
- );
- $modules[$moduleKey] = $this->createModule(
- $this->app,
- $moduleArray['name'],
- $moduleArray['path'],
- $moduleArray['namespace'],
- $moduleJson
- );
- }
-
- return $modules;
- }
-
- /**
- * Get all modules as laravel collection instance.
- *
- * @param bool $status
- *
- * @return Collection
- */
- public function collections(bool $status = true): Collection
- {
- return new Collection($this->getByStatus($status));
- }
-
- /**
- * @inheritDoc
- * @see RepositoryInterface::assetPath()
- */
- public function assetPath(string $moduleName): string
- {
- return rtrim($this->config('paths.assets'), '/') . '/' . $moduleName;
- }
-
- /**
- * @inheritDoc
- * @see RepositoryInterface::config()
- */
- public function config(string $key, $default = null)
- {
- return $this->config->get('modules.' . $key, $default);
- }
-
- /**
- * Get storage path for module used.
- */
- public function getUsedStoragePath(): string
- {
- $directory = storage_path('app/modules');
- if ($this->getFilesystem()->exists($directory) === false) {
- $this->getFilesystem()->makeDirectory($directory, 0777, true);
- }
-
- $path = storage_path('app/modules/modules.used');
- if (!$this->getFilesystem()->exists($path)) {
- $this->getFilesystem()->put($path, '');
- }
-
- return $path;
- }
-
- /**
- * Set module used for cli session.
- *
- * @throws ModuleNotFoundException
- */
- public function setUsed(string $moduleName): void
- {
- $module = $this->findOrFail($moduleName);
-
- $this->getFilesystem()->put($this->getUsedStoragePath(), $module);
- }
-
- /**
- * Forget the module used for cli session.
- */
- public function forgetUsed(): void
- {
- if ($this->getFilesystem()->exists($this->getUsedStoragePath())) {
- $this->getFilesystem()->delete($this->getUsedStoragePath());
- }
- }
-
- /**
- * Get module used for cli session.
- *
- * @throws ModuleNotFoundException|\Illuminate\Contracts\Filesystem\FileNotFoundException
- */
- public function getUsedNow(): Module
- {
- return $this->findOrFail($this->getFilesystem()->get($this->getUsedStoragePath()));
- }
-
- /**
- * Get laravel filesystem instance.
- */
- public function getFilesystem(): Filesystem
- {
- return $this->filesystem;
- }
-
- /**
- * Get modules assets path.
- */
- public function getAssetsPath(): string
- {
- return $this->config('paths.assets');
- }
-
- /**
- * Get asset url from a specific module.
- *
- * @throws InvalidAssetPath
- */
- public function asset(string $asset): string
- {
- if (Str::contains($asset, ':') === false) {
- throw InvalidAssetPath::missingModuleName($asset);
- }
- [$name, $url] = explode(':', $asset);
-
- $baseUrl = str_replace(public_path() . DIRECTORY_SEPARATOR, '', $this->getAssetsPath());
-
- $url = $this->url->asset($baseUrl . "/$name/" . $url);
-
- return str_replace(['http://', 'https://'], '//', $url);
- }
-
- /**
- * @inheritDoc
- * @see RepositoryInterface::isEnabled()
- */
- public function isEnabled(string $moduleName): bool
- {
- return $this->findOrFail($moduleName)->isEnabled();
- }
-
- /**
- * @inheritDoc
- * @see RepositoryInterface::isDisabled()
- */
- public function isDisabled(string $moduleName): bool
- {
- return !$this->isEnabled($moduleName);
- }
-
- /**
- * Enabling a specific module.
- *
- * @param string $moduleName
- *
- * @return void
- * @throws ModuleNotFoundException
- */
- public function enable(string $moduleName): void
- {
- $this->findOrFail($moduleName)->enable();
- }
-
- /**
- * Disabling a specific module.
- *
- * @param string $moduleName
- *
- * @return void
- * @throws ModuleNotFoundException
- */
- public function disable(string $moduleName): void
- {
- $this->findOrFail($moduleName)->disable();
- }
-
- /**
- * @inheritDoc
- * @see RepositoryInterface::delete()
- */
- public function delete(string $moduleName): bool
- {
- return $this->findOrFail($moduleName)->delete();
- }
-
- /**
- * Update dependencies for the specified module.
- */
- public function update(string $moduleName): void
- {
- (new Updater($this))->update($moduleName);
- }
-
- /**
- * Install the specified module.
- */
- public function install(string $name, ?string $version = 'dev-master', ?string $type = 'composer', bool $subtree = false): Process
- {
- $installer = new Installer($name, $version, $type, $subtree);
-
- return $installer->run();
- }
-
- /**
- * Flush modules cache
- */
- public function flushCache(): void
- {
- $this->cachedModules = null;
- $this->cache->forget(config('modules.cache.key'));
- $this->activator->flushCache();
- }
-}
diff --git a/src/Generators/FileGenerator.php b/src/Generators/FileGenerator.php
deleted file mode 100755
index f076bad..0000000
--- a/src/Generators/FileGenerator.php
+++ /dev/null
@@ -1,95 +0,0 @@
-path = $path;
- $this->contents = $contents;
- $this->filesystem = $filesystem ?: new Filesystem();
- }
-
- public function getContents(): string
- {
- return $this->contents;
- }
-
- public function setContents(string $contents): static
- {
- $this->contents = $contents;
-
- return $this;
- }
-
- public function getFilesystem(): Filesystem
- {
- return $this->filesystem;
- }
-
- public function setFilesystem(Filesystem $filesystem): static
- {
- $this->filesystem = $filesystem;
-
- return $this;
- }
-
- public function getPath(): string
- {
- return $this->path;
- }
-
- public function setPath(string $path): static
- {
- $this->path = $path;
-
- return $this;
- }
-
- public function withFileOverwrite(bool $overwrite): FileGenerator
- {
- $this->overwriteFile = $overwrite;
-
- return $this;
- }
-
- /**
- * Generate the file.
- *
- * @throws FileAlreadyExistException
- */
- public function generate(): bool|int
- {
- $path = $this->getPath();
-
- if ($this->overwriteFile === true || !$this->filesystem->exists($path)) {
- return $this->filesystem->put($path, $this->getContents());
- }
-
- throw new FileAlreadyExistException('File already exists!');
- }
-}
diff --git a/src/Generators/Generator.php b/src/Generators/Generator.php
deleted file mode 100755
index 12fa47f..0000000
--- a/src/Generators/Generator.php
+++ /dev/null
@@ -1,7 +0,0 @@
-module = $module;
- $this->setEntityName($entityName ?: $module->getStudlyName());
- $this->setType($type ?: 'api');
- $this->console = $console;
- }
-
- /**
- * Get the entity name.
- */
- public function getEntityName(): string
- {
- return $this->entityName ?: $this->module->getStudlyName();
- }
-
- /**
- * Set entity name.
- */
- public function setEntityName(string $entityName): static
- {
- $this->entityName = Str::studly($entityName);
-
- return $this;
- }
-
- /**
- * Get the module components type.
- *
- * @return string
- */
- public function getType(): string
- {
- return $this->type;
- }
-
- /**
- * Set the module components type.
- */
- public function setType(string $type): static
- {
- $this->type = $type;
-
- return $this;
- }
-
- /**
- * Get the laravel console instance.
- *
- * @return Console|null
- */
- public function getConsole(): ?Console
- {
- return $this->console;
- }
-
- /**
- * Set the laravel console instance.
- *
- * @param Console $console
- *
- * @return $this
- */
- public function setConsole(Console $console)
- {
- $this->console = $console;
-
- return $this;
- }
-
- public function generate(): int
- {
- $name = $this->module->getStudlyName();
- $type = $this->getType();
-
- $this->generateBaseComponentsForModule($this->module);
-
- if ($this->type === 'api') {
- $this->generateApiComponentsForModule($this->module);
- }
-
- $this->console->info("[$type] components for [$name] module created successfully.");
-
- return $this->console::SUCCESS;
- }
-
- public function generateBaseComponentsForModule(Module $module): void
- {
- $moduleName = $module->getStudlyName();
- $entityName = $this->getEntityName();
- $snakeEntityName = Str::snake($entityName);
- $snakePluralEntityName = Str::plural($snakeEntityName);
-
- if (GeneratorHelper::component('factory')->generate() === true) {
- $this->console->call('module:make:factory', [
- 'name' => "{$entityName}Factory",
- 'module' => $moduleName,
- '--model' => $entityName
- ]);
- }
-
- if (GeneratorHelper::component('migration')->generate() === true) {
- $this->console->call('module:make:migration', [
- 'name' => "create_{$snakePluralEntityName}_table",
- 'module' => $moduleName,
- '--stub' => 'create'
- ]);
- }
-
- if (GeneratorHelper::component('seeder')->generate() === true) {
- $this->console->call('module:make:seeder', [
- 'name' => "{$entityName}PermissionsSeeder_1",
- 'module' => $moduleName,
- '--stub' => 'permissions',
- '--model' => $entityName
- ]);
- }
-
- if (GeneratorHelper::component('dto')->generate() === true) {
- $this->console->call('module:make:dto', [
- 'name' => "Create{$entityName}DTO",
- 'module' => $moduleName,
- ]);
- $this->console->call('module:make:dto', [
- 'name' => "Update{$entityName}DTO",
- 'module' => $moduleName,
- ]);
- }
-
- if (GeneratorHelper::component('model')->generate() === true) {
- $this->console->call('module:make:model', [
- 'name' => $entityName,
- 'module' => $moduleName,
- '--stub' => 'full',
- '--factory' => "{$entityName}Factory"
- ]);
- }
-
- if (GeneratorHelper::component('policy')->generate() === true) {
- $this->console->call('module:make:policy', [
- 'name' => "{$entityName}Policy",
- 'module' => $moduleName,
- '--stub' => 'full',
- '--model' => $entityName
- ]);
- }
- }
-
- public function generateApiComponentsForModule(Module $module): void
- {
- $actionVerbs = ['create', 'update', 'delete', 'list', 'view'];
-
- $moduleName = $module->getStudlyName();
- $entityName = $this->getEntityName();
- $pluralEntityName = Str::plural($entityName);
- $camelEntityName = Str::camel($entityName);
- $dashedPluralEntityName = Str::snake($pluralEntityName, '-');
- $underlinedPluralEntityName = Str::snake($pluralEntityName, '_');
-
- if (GeneratorHelper::component('api-query-wizard')->generate() === true) {
- $this->console->call('module:make:wizard', [
- 'name' => "{$pluralEntityName}QueryWizard",
- 'module' => $moduleName,
- '--stub' => 'eloquent',
- ]);
- $this->console->call('module:make:wizard', [
- 'name' => "{$entityName}QueryWizard",
- 'module' => $moduleName,
- '--stub' => 'model',
- ]);
- }
-
- if (GeneratorHelper::component('api-resource')->generate() === true) {
- $this->console->call('module:make:resource', [
- 'name' => "{$entityName}Resource",
- 'module' => $moduleName,
- '--stub' => 'single'
- ]);
- }
-
- foreach ($actionVerbs as $actionVerb) {
- $studlyActionVerb = Str::studly($actionVerb);
-
- $resourceClass = "{$entityName}Resource";
- $dtoClass = "{$studlyActionVerb}{$entityName}DTO";
- $routeName = 'api.' . $underlinedPluralEntityName . '.' . $actionVerb;
-
- if ($actionVerb === "list") {
- $actionClass = "{$studlyActionVerb}{$pluralEntityName}Action";
- $requestClass = "{$studlyActionVerb}{$pluralEntityName}Request";
- $wizardClass = "{$pluralEntityName}QueryWizard";
- } else {
- $actionClass = "{$studlyActionVerb}{$entityName}Action";
- $requestClass = "{$studlyActionVerb}{$entityName}Request";
- $wizardClass = "{$entityName}QueryWizard";
- }
-
- if (GeneratorHelper::component('action')->generate() === true) {
- $this->console->call('module:make:action', [
- 'name' => $actionClass,
- 'module' => $moduleName,
- '--stub' => $actionVerb,
- '--dto' => $dtoClass,
- '--model' => $entityName,
- '--request' => $requestClass,
- '--resource' => $resourceClass,
- '--wizard' => $wizardClass
- ]);
- }
-
- if (GeneratorHelper::component("api-controller")->generate() === true) {
- $this->console->call('module:make:controller', [
- 'name' => 'Controller',
- 'module' => $moduleName,
- '--ui' => 'api'
- ]);
- }
-
- if (GeneratorHelper::component("api-request")->generate() === true) {
- $this->console->call('module:make:request', [
- 'name' => $requestClass,
- 'module' => $moduleName,
- '--ui' => 'api',
- '--dto' => $dtoClass,
- '--stub' => $actionVerb,
- '--model' => $entityName,
- ]);
- }
-
- if (GeneratorHelper::component("api-route")->generate() === true) {
- $actionMethodsMap = [
- 'create' => 'post',
- 'update' => 'patch',
- 'delete' => 'delete',
- 'list' => 'get',
- 'view' => 'get'
- ];
-
- $url = $dashedPluralEntityName;
- if (in_array($actionVerb, ['update', 'delete', 'view'])) {
- $url .= '/{' . $camelEntityName . '}';
- }
-
- $filePath = Str::snake(str_replace('Action', '', $actionClass), '_');
- $filePath = 'v1/' . $filePath;
-
- $this->console->call('module:make:route', [
- 'name' => $filePath,
- 'module' => $moduleName,
- '--ui' => 'api',
- '--action' => $actionClass,
- '--method' => $actionMethodsMap[$actionVerb],
- '--url' => $url,
- '--name' => $routeName
- ]);
- }
-
- if (GeneratorHelper::component("api-test")->generate() === true) {
- $testClass = $actionVerb === 'list'
- ? "{$studlyActionVerb}{$pluralEntityName}Test"
- : "{$studlyActionVerb}{$entityName}Test";
-
- $this->console->call('module:make:test', [
- 'name' => $testClass,
- 'module' => $moduleName,
- '--type' => 'api',
- '--stub' => $actionVerb,
- '--model' => $entityName,
- '--route' => $routeName
- ]);
- }
- }
- }
-}
diff --git a/src/Generators/ModuleGenerator.php b/src/Generators/ModuleGenerator.php
deleted file mode 100755
index 8002230..0000000
--- a/src/Generators/ModuleGenerator.php
+++ /dev/null
@@ -1,431 +0,0 @@
-name = $name;
- $this->setEntityName($entityName ?: $name);
- $this->repository = $repository;
- $this->config = $config;
- $this->filesystem = $filesystem;
- $this->console = $console;
- $this->activator = $activator;
- }
-
- /**
- * Set entity name.
- */
- public function setEntityName(string $entityName): static
- {
- $this->entityName = Str::studly($entityName);
-
- return $this;
- }
-
- /**
- * Set type.
- */
- public function setType(string $type): static
- {
- $this->type = $type;
-
- return $this;
- }
-
- /**
- * Set active flag.
- */
- public function setActive(bool $active): static
- {
- $this->isActive = $active;
-
- return $this;
- }
-
- /**
- * Get the name of the module to create. By default, in studly case.
- */
- public function getName(): string
- {
- return Str::studly($this->name);
- }
-
- /**
- * Get the entity name.
- */
- public function getEntityName(): string
- {
- return $this->entityName ?: $this->getName();
- }
-
- /**
- * Get the laravel config instance.
- */
- public function getConfig(): ?Config
- {
- return $this->config;
- }
-
- /**
- * Set the laravel config instance.
- */
- public function setConfig(Config $config): static
- {
- $this->config = $config;
-
- return $this;
- }
-
- /**
- * Set the modules activator
- */
- public function setActivator(ActivatorInterface $activator): static
- {
- $this->activator = $activator;
-
- return $this;
- }
-
- /**
- * Get the laravel filesystem instance.
- */
- public function getFilesystem(): ?Filesystem
- {
- return $this->filesystem;
- }
-
- /**
- * Set the laravel filesystem instance.
- */
- public function setFilesystem(Filesystem $filesystem): static
- {
- $this->filesystem = $filesystem;
-
- return $this;
- }
-
- /**
- * Get the laravel console instance.
- */
- public function getConsole(): ?Console
- {
- return $this->console;
- }
-
- /**
- * Set the laravel console instance.
- */
- public function setConsole(Console $console): static
- {
- $this->console = $console;
-
- return $this;
- }
-
- /**
- * Get the repository instance.
- */
- public function getRepository(): ?FileRepository
- {
- return $this->repository;
- }
-
- /**
- * Set the repository instance.
- */
- public function setRepository(FileRepository $repository): static
- {
- $this->repository = $repository;
-
- return $this;
- }
-
- /**
- * Get the list of folders to be created.
- */
- public function getFolders(): array
- {
- return $this->repository->config('generator.components');
- }
-
- /**
- * Set force status.
- */
- public function setForce($force): static
- {
- $this->force = $force;
-
- return $this;
- }
-
- /**
- * Generate the module.
- */
- public function generate(): int
- {
- $name = $this->getName();
-
- if ($this->repository->has($name)) {
- if ($this->force) {
- $this->repository->delete($name);
- } else {
- $this->console->error("Module [{$name}] already exist!");
-
- return E_ERROR;
- }
- }
-
- $this->generateFolders();
- $this->generateScaffoldFiles();
-
- $this->activator->setActiveByName($name, $this->isActive);
- $this->repository->flushCache();
-
- $this->generateProviders();
-
- if ($this->type && $this->type !== 'plain') {
- $module = $this->repository->findOrFail($name);
- $code = (new ModuleComponentsGenerator($module))
- ->setEntityName($this->entityName)
- ->setConsole($this->console)
- ->generate();
-
- if ($code === $this->console::FAILURE) {
- return $this->console::FAILURE;
- }
- }
-
- $this->console->info("Module [{$name}] created successfully.");
-
- return $this->console::SUCCESS;
- }
-
- /**
- * Generate the folders.
- */
- public function generateFolders(): void
- {
- foreach ($this->getFolders() as $key => $folder) {
- $folder = GeneratorHelper::component($key);
-
- if ($folder->generate() === false) {
- continue;
- }
-
- $path = GeneratorHelper::modulePath($this->getName(), $folder->getPath());
-
- if (!$this->filesystem->isDirectory($path)) {
- $this->filesystem->makeDirectory($path, 0755, true);
- if ($folder->withGitKeep()) {
- $this->generateGitKeep($path);
- }
- }
- }
- }
-
- public function generateScaffoldFiles(): void
- {
- $this->generateComposerJsonFile();
- $this->generateModuleJsonFile();
- }
-
- /**
- * Generate module providers.
- */
- public function generateProviders(): void
- {
- if (!GeneratorHelper::component('provider')->generate()) {
- return;
- }
-
- $moduleName = $this->getName();
-
- $this->console->call('module:make:provider', [
- 'name' => "{$moduleName}ServiceProvider",
- 'module' => $moduleName,
- '--stub' => 'module'
- ]);
-
- $this->console->call('module:make:provider', [
- 'name' => "RouteServiceProvider",
- 'module' => $moduleName,
- '--stub' => 'route'
- ]);
- }
-
- /**
- * Generate git keep to the specified path.
- */
- protected function generateGitKeep(string $path): void
- {
- $this->filesystem->put($path . '/.gitkeep', '');
- }
-
- /**
- * Generate composer.json
- */
- protected function generateComposerJsonFile(): void
- {
- $path = GeneratorHelper::modulePath($this->getName(), 'composer.json');
-
- $stubContent = (new Stub('/composer.json.stub', $this->getAllReplacements()))->render();
-
- $this->createFile($path, $stubContent);
- }
-
- /**
- * Generate the module.json file
- */
- protected function generateModuleJsonFile(): void
- {
- $path = GeneratorHelper::modulePath($this->getName(), 'module.json');
-
- $stubContent = (new Stub('/module.json.stub', $this->getAllReplacements()))->render();
-
- $this->createFile($path, $stubContent);
- }
-
- /**
- * Create a file at the given path, after creating folders if necessary
- */
- protected function createFile(string $path, string $content): void
- {
- $this->filesystem->ensureDirectoryExists(dirname($path));
- $this->filesystem->put($path, $content);
-
- $this->console->info("Created: `$path`");
- }
-
- /**
- * Get replacements
- */
- protected function getAllReplacements(): array
- {
- return [
- 'authorEmail' => $this->getAuthorEmailReplacement(),
- 'authorName' => $this->getAuthorNameReplacement(),
- 'moduleKey' => $this->getModuleKeyReplacement(),
- 'moduleName' => $this->getModuleNameReplacement(),
- 'moduleNamespace' => $this->getModuleNamespaceReplacement(),
- 'vendor' => $this->getVendorReplacement()
- ];
- }
-
- /**
- * Get replacement for {{ moduleKey }}.
- */
- protected function getModuleKeyReplacement(): string
- {
- return Modules::getModuleKey($this->getName());
- }
-
- /**
- * Get the module name in studly case (replacement for {{ moduleName }}).
- */
- protected function getModuleNameReplacement(): string
- {
- return $this->getName();
- }
-
- /**
- * Get replacement for {{ vendor }}.
- */
- protected function getVendorReplacement(): string
- {
- return $this->repository->config('composer.vendor', '');
- }
-
- /**
- * Get replacement for {{ authorName }}.
- */
- protected function getAuthorNameReplacement(): string
- {
- return $this->repository->config('composer.author.name', '');
- }
-
- /**
- * Get replacement for {{ authorEmail }}.
- */
- protected function getAuthorEmailReplacement(): string
- {
- return $this->repository->config('composer.author.email', '');
- }
-
- /**
- * Get replacement for {{ moduleNamespace }}.
- */
- protected function getModuleNamespaceReplacement(): string
- {
- return str_replace('\\', '\\\\', GeneratorHelper::moduleNamespace($this->getName()));
- }
-}
diff --git a/src/Json.php b/src/Json.php
deleted file mode 100755
index ecee94f..0000000
--- a/src/Json.php
+++ /dev/null
@@ -1,200 +0,0 @@
-path = $path;
- $this->filesystem = $filesystem ?: new Filesystem();
- $this->attributes = Collection::make($cachedAttributes ?? $this->retrieveRawAttributes());
- }
-
- /**
- * Make new instance.
- */
- public static function make(string $path, ?Filesystem $filesystem = null, ?array $cachedAttributes = null): static
- {
- return new static($path, $filesystem, $cachedAttributes);
- }
-
- public function getFilesystem(): Filesystem
- {
- return $this->filesystem;
- }
-
- public function setFilesystem(Filesystem $filesystem): static
- {
- $this->filesystem = $filesystem;
-
- return $this;
- }
-
- public function getPath(): string
- {
- return $this->path;
- }
-
- public function setPath($path): static
- {
- $this->path = (string) $path;
-
- return $this;
- }
-
- public function getAttributes(): Collection
- {
- return $this->attributes;
- }
-
- /**
- * Get file contents as array.
- *
- * @throws FileNotFoundException|JsonException
- */
- public function retrieveRawAttributes(): array
- {
- return json_decode($this->getContents(), true, 512, JSON_THROW_ON_ERROR);
- }
-
- /**
- * Get file content.
- *
- * @return string
- * @throws FileNotFoundException
- */
- public function getContents(): string
- {
- return $this->filesystem->get($this->getPath());
- }
-
- /**
- * Convert the given array data to pretty json.
- *
- * @throws JsonException
- */
- public function toJsonPretty(): string
- {
- return json_encode($this->attributes, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT);
- }
-
- /**
- * Update json contents from array data.
- *
- * @throws FileNotFoundException|JsonException
- */
- public function update(array $data): int|false
- {
- $this->attributes = new Collection(array_merge($this->attributes->toArray(), $data));
-
- return $this->save();
- }
-
- /**
- * Save the current attributes array to the file storage.
- *
- * @throws JsonException
- */
- public function save(): int|false
- {
- return $this->filesystem->put($this->getPath(), $this->toJsonPretty());
- }
-
- /**
- * Get json attributes as plain array
- */
- public function toArray(): array
- {
- return [
- 'path' => $this->path,
- 'attributes' => $this->attributes->toArray(),
- ];
- }
-
- /**
- * Get the specified attribute from json file.
- */
- public function get($key, $default = null)
- {
- return $this->attributes->get($key, $default);
- }
-
- /**
- * Set a specific key & value.
- */
- public function set($key, $value): static
- {
- $this->attributes->offsetSet($key, $value);
-
- return $this;
- }
-
- /**
- * Handle magic method __get.
- */
- public function __get($key)
- {
- return $this->get($key);
- }
-
- /**
- * Handle magic method __set.
- */
- public function __set($key, $value)
- {
- $this->set($key, $value);
- }
-
- /**
- * Handle magic method __isset.
- */
- public function __isset(string $name): bool
- {
- return $this->attributes->offsetExists($name);
- }
-
- /**
- * Handle call to __call method.
- */
- public function __call(string $method, array $arguments = [])
- {
- if (method_exists($this, $method)) {
- return call_user_func_array([$this, $method], $arguments);
- }
-
- return call_user_func_array([$this->attributes, $method], $arguments);
- }
-
- /**
- * Handle call to __toString method.
- *
- * @return string
- * @throws FileNotFoundException
- */
- public function __toString()
- {
- return $this->getContents();
- }
-}
diff --git a/src/Migrations/Migrator.php b/src/Migrations/Migrator.php
deleted file mode 100755
index c0d6be5..0000000
--- a/src/Migrations/Migrator.php
+++ /dev/null
@@ -1,261 +0,0 @@
-module = $module;
- $this->laravel = $application;
- }
-
- /**
- * Set the database connection to be used
- */
- public function setDatabase(string $database): static
- {
- if ($database) {
- $this->database = $database;
- }
-
- return $this;
- }
-
- /**
- * Get module instance.
- */
- public function getModule(): Module
- {
- return $this->module;
- }
-
- /**
- * Get migration path.
- */
- public function getPath(): string
- {
- $config = $this->module->get('migration');
-
- $migrationPath = GeneratorHelper::component('migration');
- $path = (is_array($config) && array_key_exists('path', $config)) ? $config['path'] : $migrationPath->getPath();
-
- return $this->module->getExtraPath($path);
- }
-
- /**
- * Get migration files.
- */
- public function getMigrations(bool $reverse = false): array
- {
- $files = $this->laravel['files']->glob($this->getPath() . '/*_*.php');
-
- // Once we have the array of files in the directory we will just remove the
- // extension and take the basename of the file which is all we need when
- // finding the migrations that haven't been run against the databases.
- if ($files === false) {
- return [];
- }
-
- $files = array_map(static function ($file) {
- return str_replace('.php', '', basename($file));
- }, $files);
-
- // Once we have all of the formatted file names we will sort them and since
- // they all start with a timestamp this should give us the migrations in
- // the order they were actually created by the application developers.
- sort($files);
-
- if ($reverse) {
- return array_reverse($files);
- }
-
- return $files;
- }
-
- /**
- * Rollback migration.
- */
- public function rollback(): array
- {
- $migrations = $this->getLast($this->getMigrations(true));
-
- $this->requireFiles($migrations->toArray());
-
- $migrated = [];
-
- foreach ($migrations as $migration) {
- $data = $this->find($migration);
-
- if ($data->count()) {
- $migrated[] = $migration;
-
- $this->down($migration);
-
- $data->delete();
- }
- }
-
- return $migrated;
- }
-
- /**
- * Reset migration.
- */
- public function reset(): array
- {
- $migrations = $this->getMigrations(true);
-
- $this->requireFiles($migrations);
-
- $migrated = [];
-
- foreach ($migrations as $migration) {
- $data = $this->find($migration);
-
- if ($data->count()) {
- $migrated[] = $migration;
-
- $this->down($migration);
-
- $data->delete();
- }
- }
-
- return $migrated;
- }
-
- /**
- * Run down schema from the given migration name.
- */
- public function down(string $migration): void
- {
- $this->resolve($migration)->down();
- }
-
- /**
- * Run up schema from the given migration name.
- */
- public function up(string $migration): void
- {
- $this->resolve($migration)->up();
- }
-
- /**
- * Resolve a migration instance from a file.
- */
- public function resolve(string $file): object
- {
- $file = implode('_', array_slice(explode('_', $file), 4));
-
- $class = Str::studly($file);
-
- return new $class();
- }
-
- /**
- * Require in all the migration files in a given path.
- */
- public function requireFiles(array $files): void
- {
- $path = $this->getPath();
- foreach ($files as $file) {
- $this->laravel['files']->requireOnce($path . '/' . $file . '.php');
- }
- }
-
- /**
- * Get table instance.
- */
- public function table(): Builder
- {
- return $this->laravel['db']->connection($this->database ?: null)->table(config('database.migrations'));
- }
-
- /**
- * Find migration data from database by given migration name.
- */
- public function find(string $migration): Builder
- {
- return $this->table()->where('migration', $migration);
- }
-
- /**
- * Save new migration to database.
- */
- public function log(string $migration): bool
- {
- return $this->table()->insert([
- 'migration' => $migration,
- 'batch' => $this->getNextBatchNumber(),
- ]);
- }
-
- /**
- * Get the next migration batch number.
- */
- public function getNextBatchNumber(): int
- {
- return $this->getLastBatchNumber() + 1;
- }
-
- /**
- * Get the last migration batch number.
- */
- public function getLastBatchNumber(?array $migrations = null): int
- {
- $table = $this->table();
-
- if (is_array($migrations)) {
- $table = $table->whereIn('migration', $migrations);
- }
-
- return $table->max('batch');
- }
-
- /**
- * Get the last migration batch.
- */
- public function getLast(array $migrations): Collection
- {
- $query = $this->table()
- ->where('batch', $this->getLastBatchNumber($migrations))
- ->whereIn('migration', $migrations);
-
- $result = $query->orderBy('migration', 'desc')->get();
-
- return collect($result)->map(function ($item) {
- return (array) $item;
- })->pluck('migration');
- }
-
- /**
- * Get the ran migrations.
- */
- public function getRan(): Collection
- {
- return $this->table()->pluck('migration');
- }
-}
diff --git a/src/Module.php b/src/Module.php
index b8056b8..108ad82 100755
--- a/src/Module.php
+++ b/src/Module.php
@@ -2,86 +2,59 @@
namespace Laraneat\Modules;
-use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Support\Arrayable;
-use Illuminate\Filesystem\Filesystem;
-use Illuminate\Foundation\AliasLoader;
-use Illuminate\Foundation\ProviderRepository;
-use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable;
-use Laraneat\Modules\Contracts\ActivatorInterface;
-use Laraneat\Modules\Facades\Modules;
+use Laraneat\Modules\Support\Generator\GeneratorHelper;
+/**
+ * @implements Arrayable
+ */
class Module implements Arrayable
{
use Macroable;
- /**
- * The laravel application instance.
- */
- protected Application $app;
-
- /**
- * The module name.
- */
+ protected string $packageName;
protected string $name;
-
- /**
- * The module path.
- */
protected string $path;
-
- /**
- * The module namespace.
- */
protected string $namespace;
/**
- * @var array of cached Json objects, keyed by filename
- */
- protected array $moduleJson = [];
-
- /**
- * The laravel filesystem instance.
+ * @param string $packageName The module package name.
+ * @param string $name The module name.
+ * @param string $path The module path.
+ * @param string $namespace The module namespace.
+ * @param array $providers Module providers
+ * @param array $aliases Module aliases
*/
- private Filesystem $filesystem;
-
- /**
- * The activator instance.
- */
- private ActivatorInterface $activator;
-
public function __construct(
- Application $app,
+ string $packageName,
string $name,
string $path,
string $namespace,
- array $moduleJson = []
+ protected array $providers = [],
+ protected array $aliases = [],
) {
- $this->app = $app;
- $this->name = trim($name);
+ $this->packageName = trim($packageName);
+ $this->name = trim($name) ?: Str::afterLast($this->packageName, '/');
$this->path = rtrim($path, '/');
$this->namespace = trim($namespace, '\\');
- $this->moduleJson = $moduleJson;
- $this->filesystem = $app['files'];
- $this->activator = $app[ActivatorInterface::class];
}
/**
- * Get name.
+ * Get package name.
*/
- public function getName(): string
+ public function getPackageName(): string
{
- return $this->name;
+ return $this->packageName;
}
/**
- * Get key.
+ * Get name.
*/
- public function getKey(): string
+ public function getName(): string
{
- return Str::snake($this->name, '-');
+ return $this->name;
}
/**
@@ -93,43 +66,19 @@ public function getStudlyName(): string
}
/**
- * Get name in snake case.
+ * Get name in kebab case.
*/
- public function getSnakeName(): string
+ public function getKebabName(): string
{
- return Str::snake($this->name);
+ return Str::kebab(str_replace('_', '-', $this->name));
}
/**
- * Get description.
- */
- public function getDescription(): string
- {
- return $this->get('description');
- }
-
- /**
- * Get alias.
- */
- public function getAlias(): string
- {
- return $this->get('alias');
- }
-
- /**
- * Get priority.
- */
- public function getPriority(): string
- {
- return $this->get('priority');
- }
-
- /**
- * Get module requirements.
+ * Get name in snake case.
*/
- public function getRequires(): array
+ public function getSnakeName(): string
{
- return $this->get('requires');
+ return Str::snake(str_replace('-', '_', $this->name));
}
/**
@@ -149,230 +98,68 @@ public function getNamespace(): string
}
/**
- * Bootstrap the application events.
- */
- public function boot(): void
- {
- if ($this->isLoadFilesOnBoot()) {
- $this->registerFiles();
- }
-
- $this->fireEvent('boot');
- }
-
- /**
- * Get json contents from the cache, setting as needed.
- */
- public function json(?string $fileName = 'module.json'): Json
- {
- if ($fileName === null) {
- $fileName = 'module.json';
- }
-
- return Arr::get($this->moduleJson, $fileName, function () use ($fileName) {
- return $this->moduleJson[$fileName] = Json::make($this->getExtraPath($fileName), $this->filesystem);
- });
- }
-
- /**
- * Get a specific data from json file by given the key.
+ * Get module providers.
+ *
+ * @return array
*/
- public function get(string $key, $default = null)
+ public function getProviders(): array
{
- return $this->json()->get($key, $default);
+ return $this->providers;
}
/**
- * Get a specific data from composer.json file by given the key.
+ * Get module aliases.
+ *
+ * @return array
*/
- public function getComposerAttr(string $key, $default = null)
+ public function getAliases(): array
{
- return $this->json('composer.json')->get($key, $default);
+ return $this->aliases;
}
/**
- * Register the module.
+ * Get sub path.
*/
- public function register(): void
+ public function subPath(string $subPath): string
{
- $this->registerAliases();
- $this->registerProviders();
-
- if ($this->isLoadFilesOnBoot() === false) {
- $this->registerFiles();
- }
-
- $this->fireEvent('register');
+ return $this->getPath() . '/' . GeneratorHelper::normalizePath($subPath);
}
/**
- * Register the module event.
+ * Get sub namespace.
*/
- protected function fireEvent(string $event): void
+ public function subNamespace(string $subNamespace): string
{
- $this->app['events']->dispatch(sprintf('modules.%s.' . $event, $this->getKey()), [$this]);
- }
-
- /**
- * Get the path to the cached *_module.php file.
- */
- public function getCachedServicesPath(): string
- {
- // This checks if we are running on a Laravel Vapor managed instance
- // and sets the path to a writable one (services path is not on a writable storage in Vapor).
- if (!is_null(env('VAPOR_MAINTENANCE_MODE', null))) {
- return Str::replaceLast('config.php', $this->getSnakeName() . '_module.php', $this->app->getCachedConfigPath());
- }
-
- return Str::replaceLast('services.php', $this->getSnakeName() . '_module.php', $this->app->getCachedServicesPath());
- }
-
- /**
- * Register the service providers from this module.
- */
- public function registerProviders(): void
- {
- (new ProviderRepository($this->app, new Filesystem(), $this->getCachedServicesPath()))
- ->load($this->get('providers', []));
- }
-
- /**
- * Register the aliases from this module.
- */
- public function registerAliases(): void
- {
- $loader = AliasLoader::getInstance();
- foreach ($this->get('aliases', []) as $aliasName => $aliasClass) {
- $loader->alias($aliasName, $aliasClass);
- }
- }
-
- /**
- * Register the files from this module.
- */
- protected function registerFiles(): void
- {
- foreach ($this->get('files', []) as $fileName) {
- include $this->path . '/' . $fileName;
- }
+ return $this->getNamespace() . '\\' . GeneratorHelper::normalizeNamespace($subNamespace);
}
/**
* Handle call __toString.
*/
- public function __toString()
- {
- return $this->getStudlyName();
- }
-
- /**
- * Determine whether the given status same with the current module status.
- */
- public function isStatus(bool $status): bool
- {
- return $this->activator->hasStatus($this, $status);
- }
-
- /**
- * Determine whether the current module activated.
- */
- public function isEnabled(): bool
- {
- return $this->activator->hasStatus($this, true);
- }
-
- /**
- * Determine whether the current module not disabled.
- */
- public function isDisabled(): bool
- {
- return !$this->isEnabled();
- }
-
- /**
- * Set active state for current module.
- */
- public function setActive(bool $active): void
- {
- $this->activator->setActive($this, $active);
- }
-
- /**
- * Disable the current module.
- */
- public function disable(): void
+ public function __toString(): string
{
- $this->fireEvent('disabling');
-
- $this->activator->disable($this);
- $this->flushCache();
-
- $this->fireEvent('disabled');
- }
-
- /**
- * Enable the current module.
- */
- public function enable(): void
- {
- $this->fireEvent('enabling');
-
- $this->activator->enable($this);
- $this->flushCache();
-
- $this->fireEvent('enabled');
- }
-
- /**
- * Delete the current module.
- */
- public function delete(): bool
- {
- $this->fireEvent('deleting');
-
- $this->activator->delete($this);
- $status = $this->json()->getFilesystem()->deleteDirectory($this->getPath());
- $this->flushCache();
-
- $this->fireEvent('deleted');
-
- return $status;
+ return $this->getPackageName();
}
/**
- * Get extra path.
- */
- public function getExtraPath(string $path): string
- {
- return $this->getPath() . '/' . ltrim($path, '/');
- }
-
- /**
- * Check if the module files can be loaded on boot.
- */
- protected function isLoadFilesOnBoot(): bool
- {
- return config('modules.register.files', 'register') === 'boot';
- }
-
- /**
- * Get the module as a plain array.
+ * @return array{
+ * path: string,
+ * packageName: string,
+ * name: string,
+ * namespace: string,
+ * providers: array,
+ * aliases: array
+ * }
*/
public function toArray(): array
{
return [
- 'name' => $this->name,
'path' => $this->path,
+ 'packageName' => $this->packageName,
+ 'name' => $this->name,
'namespace' => $this->namespace,
- 'module_json' => array_map(static fn (Json $json) => $json->toArray(), $this->moduleJson)
+ 'providers' => $this->providers,
+ 'aliases' => $this->aliases,
];
}
-
- /**
- * Flush modules cache.
- */
- protected function flushCache(): void
- {
- Modules::flushCache();
- }
}
diff --git a/src/ModulesRepository.php b/src/ModulesRepository.php
new file mode 100644
index 0000000..62152af
--- /dev/null
+++ b/src/ModulesRepository.php
@@ -0,0 +1,396 @@
+
+ */
+ protected array $scanPaths = [];
+
+ /**
+ * The loaded modules array.
+ *
+ * @var array|null
+ */
+ protected ?array $modules = null;
+
+ /**
+ * Create a new module manifest instance.
+ */
+ public function __construct(
+ protected Filesystem $filesystem,
+ protected Composer $composer,
+ protected string $modulesPath,
+ protected string $basePath,
+ protected ?string $modulesManifestPath = null,
+ ) {
+ $this->addScanPath($this->modulesPath);
+ }
+
+ /**
+ * Get module scan paths.
+ *
+ * @return array
+ */
+ public function getScanPaths(): array
+ {
+ return $this->scanPaths;
+ }
+
+ /**
+ * Add module scan path.
+ *
+ * @param string|array $scanPaths
+ *
+ * @return $this
+ */
+ public function addScanPath(string|array $scanPaths): static
+ {
+ foreach (Arr::wrap($scanPaths) as $scanPath) {
+ $normalizedScanPath = $this->normalizeScanPath($scanPath);
+
+ if (! $normalizedScanPath || in_array($normalizedScanPath, $this->scanPaths, true)) {
+ continue;
+ }
+
+ $this->scanPaths[] = $normalizedScanPath;
+ }
+
+ $this->modules = null;
+
+ return $this;
+ }
+
+ /**
+ * Build the modules manifest and write it to disk if cache enabled.
+ *
+ * @return array }>
+ *
+ * @throws ModuleHasNoNamespace
+ * @throws ModuleHasNonUniquePackageName
+ */
+ public function buildModulesManifest(): array
+ {
+ $modulesManifest = [];
+
+ foreach ($this->scanPaths as $path) {
+ $packagePaths = $this->filesystem->glob("$path/composer.json");
+
+ foreach ($packagePaths as $packagePath) {
+ $packagePath = GeneratorHelper::normalizePath($packagePath, true);
+ $composerJsonFile = ComposerJsonFile::create($packagePath);
+ $packageName = trim($composerJsonFile->get('name') ?? "");
+
+ if (! $packageName) {
+ continue;
+ }
+
+ if (array_key_exists($packageName, $modulesManifest)) {
+ throw ModuleHasNonUniquePackageName::make($packageName);
+ }
+
+ $path = str_replace('\\', '/', dirname($packagePath));
+
+ $moduleData = [
+ 'path' => $path,
+ 'name' => basename($path),
+ 'namespace' => array_key_first($composerJsonFile->get('autoload.psr-4') ?? []),
+ 'providers' => $composerJsonFile->get('extra.laravel.providers') ?? [],
+ 'aliases' => $composerJsonFile->get('extra.laravel.aliases') ?? [],
+ ];
+
+ $modulesManifest[$packageName] = $this->validateModuleData($packageName, $moduleData);
+ }
+ }
+
+ if ($this->modulesManifestPath) {
+ $this->write($modulesManifest, $this->modulesManifestPath);
+ }
+
+ return $modulesManifest;
+ }
+
+ /**
+ * Prune modules manifest
+ */
+ public function pruneModulesManifest(): bool
+ {
+ $this->modules = null;
+
+ if ($this->modulesManifestPath === null) {
+ return true;
+ }
+
+ return $this->filesystem->delete($this->modulesManifestPath);
+ }
+
+ /**
+ * Get discovered modules
+ *
+ * @return array
+ *
+ * @throws ModuleHasNoNamespace
+ * @throws ModuleHasNonUniquePackageName
+ */
+ public function getModules(): array
+ {
+ if ($this->modules !== null) {
+ return $this->modules;
+ }
+
+ try {
+ if ($this->modulesManifestPath && $this->filesystem->isFile($this->modulesManifestPath)) {
+ return $this->modules = $this->makeModulesFromManifest(
+ $this->filesystem->getRequire($this->modulesManifestPath)
+ );
+ }
+ } catch (FileNotFoundException) {
+ // Manifest file not found, will rebuild
+ }
+
+ return $this->modules = $this->makeModulesFromManifest($this->buildModulesManifest());
+ }
+
+ /**
+ * Determine whether the given module exist by its package name.
+ */
+ public function has(string $modulePackageName): bool
+ {
+ return array_key_exists($modulePackageName, $this->getModules());
+ }
+
+ /**
+ * Get count from all modules.
+ */
+ public function count(): int
+ {
+ return count($this->getModules());
+ }
+
+ /**
+ * Find a specific module by its package name.
+ */
+ public function find(string $modulePackageName): ?Module
+ {
+ $modulePackageName = trim($modulePackageName);
+
+ return $this->getModules()[$modulePackageName] ?? null;
+ }
+
+ /**
+ * Find a specific module by its package name, if there return that, otherwise throw exception.
+ *
+ * @throws ModuleNotFound
+ */
+ public function findOrFail(string $modulePackageName): Module
+ {
+ $module = $this->find($modulePackageName);
+
+ if ($module === null) {
+ throw ModuleNotFound::make($modulePackageName);
+ }
+
+ return $module;
+ }
+
+ /**
+ * Filter modules by name.
+ *
+ * @return array
+ */
+ public function filterByName(string $moduleName): array
+ {
+ $moduleName = trim($moduleName);
+ $moduleKebabName = Str::kebab($moduleName);
+ $moduleStudlyName = Str::studly($moduleName);
+ $foundModules = [];
+
+ foreach ($this->getModules() as $modulePackageName => $module) {
+ $modulePackageNameWithoutVendor = Str::kebab(Str::afterLast($modulePackageName, '/'));
+ if ($module->getStudlyName() === $moduleStudlyName || $modulePackageNameWithoutVendor === $moduleKebabName) {
+ $foundModules[$modulePackageName] = $module;
+ }
+ }
+
+ return $foundModules;
+ }
+
+ /**
+ * Find a specific module by its name, if there return that, otherwise throw exception.
+ *
+ * @return array
+ *
+ * @throws ModuleNotFound
+ */
+ public function filterByNameOrFail(string $moduleName): array
+ {
+ $modules = $this->filterByName($moduleName);
+
+ if (! $modules) {
+ throw ModuleNotFound::makeForName($moduleName);
+ }
+
+ return $modules;
+ }
+
+ /**
+ * Delete a specific module by its package name.
+ *
+ * @throws ModuleNotFound
+ * @throws ComposerException
+ */
+ public function delete(string $modulePackageName, \Closure|OutputInterface $output = null): bool
+ {
+ $module = $this->findOrFail($modulePackageName);
+
+ $result = $this->filesystem->deleteDirectory($module->getPath());
+
+ if (! $this->composer->removePackages([$module->getPackageName()], false, $output)) {
+ throw ComposerException::make("Failed to remove package with composer.");
+ }
+
+ $this->pruneModulesManifest();
+
+ return $result;
+ }
+
+ /**
+ * Sync modules with composer.
+ *
+ * @throws ModuleHasNoNamespace
+ * @throws ModuleHasNonUniquePackageName
+ * @throws ComposerException
+ */
+ public function syncWithComposer(\Closure|OutputInterface $output = null): void
+ {
+ $composerJsonPath = $this->basePath . '/' . Factory::getComposerFile();
+ $composerJsonFile = ComposerJsonFile::create($composerJsonPath);
+
+ foreach ($this->getModules() as $modulePackageName => $module) {
+ $moduleRelativePath = GeneratorHelper::makeRelativePath($this->basePath, $module->getPath());
+ if ($moduleRelativePath !== null) {
+ $composerJsonFile->addModule($modulePackageName, $moduleRelativePath);
+ }
+ }
+
+ $composerJsonFile->save();
+
+ $modulePackageNames = array_keys($this->getModules());
+ if (! $modulePackageNames) {
+ return;
+ }
+
+ if (! $this->composer->updatePackages($modulePackageNames, false, $output)) {
+ throw ComposerException::make("Failed to update package with composer.");
+ }
+ }
+
+ /**
+ * @return array,
+ * aliases: array
+ * }>
+ */
+ public function toArray(): array
+ {
+ return array_map(static fn (Module $module) => $module->toArray(), $this->getModules());
+ }
+
+ /**
+ * Write the given manifest array to disk.
+ *
+ * @param array $manifest
+ *
+ * @throws DirectoryMustBePresentAndWritable
+ */
+ protected function write(array $manifest, string $manifestPath): void
+ {
+ if (! is_writable($dirname = dirname($manifestPath))) {
+ throw DirectoryMustBePresentAndWritable::make($dirname);
+ }
+
+ $this->filesystem->replace(
+ $manifestPath,
+ ' } $moduleData
+ *
+ * @return array{ path: string, name: string, namespace: string, providers: class-string[], aliases: array }
+ *
+ * @throws ModuleHasNoNamespace
+ */
+ protected function validateModuleData(string $packageName, array $moduleData): array
+ {
+ if (empty(trim($moduleData['namespace'] ?? ""))) {
+ throw ModuleHasNoNamespace::make($packageName);
+ }
+
+ return $moduleData;
+ }
+
+ /**
+ * Make Module instances from manifest
+ *
+ * @param array }> $manifest
+ *
+ * @return array
+ */
+ protected function makeModulesFromManifest(array $manifest): array
+ {
+ return collect($manifest)
+ ->map(fn ($module, $packageName) => $this->makeModuleFromManifestItem($packageName, $module))
+ ->all();
+ }
+
+ /**
+ * @param string $packageName
+ * @param array{ path: string, name: string, namespace: string, providers: class-string[], aliases: array } $moduleData
+ */
+ protected function makeModuleFromManifestItem(string $packageName, array $moduleData): Module
+ {
+ return new Module(
+ packageName: $packageName,
+ name: $moduleData['name'],
+ path: $moduleData['path'],
+ namespace: $moduleData['namespace'],
+ providers: $moduleData['providers'],
+ aliases: $moduleData['aliases'],
+ );
+ }
+}
diff --git a/src/ModulesServiceProvider.php b/src/ModulesServiceProvider.php
deleted file mode 100755
index 0c761a6..0000000
--- a/src/ModulesServiceProvider.php
+++ /dev/null
@@ -1,57 +0,0 @@
-mergeConfigFrom(__DIR__ . '/../config/config.php', 'modules');
- $this->registerServices();
- $this->app->register(ConsoleServiceProvider::class);
- }
-
- /**
- * Bootstrap any application services.
- */
- public function boot(): void
- {
- if (app()->runningInConsole()) {
- $this->publishes([
- __DIR__ . '/../config/config.php' => config_path('modules.php'),
- ], 'config');
- }
- $this->app->register(BootstrapServiceProvider::class);
- }
-
- protected function registerServices(): void
- {
- $this->app->alias(RepositoryInterface::class, 'modules');
- $this->app->singleton(RepositoryInterface::class, function ($app) {
- $path = $app['config']->get('modules.generator.path');
-
- return new FileRepository($app, $path);
- });
-
- $this->app->singleton(ActivatorInterface::class, function ($app) {
- $activator = $app['config']->get('modules.activator');
- $class = $app['config']->get('modules.activators.' . $activator)['class'];
-
- if ($class === null) {
- throw InvalidActivatorClass::missingConfig();
- }
-
- return new $class($app);
- });
- }
-}
diff --git a/src/Process/Installer.php b/src/Process/Installer.php
deleted file mode 100755
index 2b13af2..0000000
--- a/src/Process/Installer.php
+++ /dev/null
@@ -1,309 +0,0 @@
-name = $name;
- $this->version = $version;
- $this->type = $type;
- $this->tree = $tree;
- }
-
- /**
- * Set destination path.
- *
- * @param string $path
- *
- * @return $this
- */
- public function setPath(string $path)
- {
- $this->path = $path;
-
- return $this;
- }
-
- /**
- * Set the module repository instance.
- *
- * @param RepositoryInterface $repository
- *
- * @return $this
- */
- public function setRepository(RepositoryInterface $repository)
- {
- $this->repository = $repository;
-
- return $this;
- }
-
- /**
- * Set console command instance.
- *
- * @param Command $console
- *
- * @return $this
- */
- public function setConsole(Command $console)
- {
- $this->console = $console;
-
- return $this;
- }
-
- /**
- * Set process timeout.
- *
- * @param int $timeout
- *
- * @return $this
- */
- public function setTimeout(int $timeout)
- {
- $this->timeout = $timeout;
-
- return $this;
- }
-
- /**
- * Run the installation process.
- *
- * @return Process
- */
- public function run(): Process
- {
- $process = $this->getProcess();
-
- $process->setTimeout($this->timeout);
-
- if ($this->console instanceof Command) {
- $process->run(function ($type, $line) {
- $this->console->line($line);
- });
- }
-
- return $process;
- }
-
- /**
- * Get process instance.
- *
- * @return Process
- */
- public function getProcess(): Process
- {
- if ($this->type) {
- if ($this->tree) {
- return $this->installViaSubtree();
- }
-
- return $this->installViaGit();
- }
-
- return $this->installViaComposer();
- }
-
- /**
- * Get destination path.
- *
- * @return string
- */
- public function getDestinationPath(): string
- {
- if ($this->path) {
- return $this->path;
- }
-
- return GeneratorHelper::path() . '/' . $this->getModuleName();
- }
-
- /**
- * Get git repo url.
- *
- * @return string|null
- */
- public function getRepoUrl(): ?string
- {
- switch ($this->type) {
- case 'github':
- return "git@github.com:{$this->name}.git";
-
- case 'github-https':
- return "https://github.com/{$this->name}.git";
-
- case 'gitlab':
- return "git@gitlab.com:{$this->name}.git";
- break;
-
- case 'bitbucket':
- return "git@bitbucket.org:{$this->name}.git";
-
- default:
- // Check of type 'scheme://host/path'
- if (filter_var($this->type, FILTER_VALIDATE_URL)) {
- return $this->type;
- }
-
- // Check of type 'user@host'
- if (filter_var($this->type, FILTER_VALIDATE_EMAIL)) {
- return "{$this->type}:{$this->name}.git";
- }
-
- return null;
- }
- }
-
- /**
- * Get branch name.
- *
- * @return string
- */
- public function getBranch(): string
- {
- return is_null($this->version) ? 'master' : $this->version;
- }
-
- /**
- * Get module name.
- *
- * @return string
- */
- public function getModuleName(): string
- {
- $parts = explode('/', $this->name);
-
- return Str::studly(end($parts));
- }
-
- /**
- * Get composer package name.
- *
- * @return string
- */
- public function getPackageName(): string
- {
- if (is_null($this->version)) {
- return $this->name . ':dev-master';
- }
-
- return $this->name . ':' . $this->version;
- }
-
- /**
- * Install the module via git.
- *
- * @return Process
- */
- public function installViaGit(): Process
- {
- return Process::fromShellCommandline(sprintf(
- 'cd %s && git clone %s %s && cd %s && git checkout %s',
- base_path(),
- $this->getRepoUrl(),
- $this->getDestinationPath(),
- $this->getDestinationPath(),
- $this->getBranch()
- ));
- }
-
- /**
- * Install the module via git subtree.
- *
- * @return Process
- */
- public function installViaSubtree(): Process
- {
- return Process::fromShellCommandline(sprintf(
- 'cd %s && git remote add %s %s && git subtree add --prefix=%s --squash %s %s',
- base_path(),
- $this->getModuleName(),
- $this->getRepoUrl(),
- $this->getDestinationPath(),
- $this->getModuleName(),
- $this->getBranch()
- ));
- }
-
- /**
- * Install the module via composer.
- *
- * @return Process
- */
- public function installViaComposer(): Process
- {
- return Process::fromShellCommandline(sprintf(
- 'cd %s && composer require %s',
- base_path(),
- $this->getPackageName()
- ));
- }
-}
diff --git a/src/Process/Runner.php b/src/Process/Runner.php
deleted file mode 100755
index 6ebb766..0000000
--- a/src/Process/Runner.php
+++ /dev/null
@@ -1,30 +0,0 @@
-repository = $repository;
- }
-
- /**
- * Run the given command.
- *
- * @param string $command
- */
- public function run(string $command): void
- {
- passthru($command);
- }
-}
diff --git a/src/Process/Updater.php b/src/Process/Updater.php
deleted file mode 100755
index c8d37c0..0000000
--- a/src/Process/Updater.php
+++ /dev/null
@@ -1,88 +0,0 @@
-repository->findOrFail($moduleName);
-
- chdir(base_path());
-
- $this->installRequires($module);
- $this->installDevRequires($module);
- $this->copyScriptsToMainComposerJson($module);
- }
-
- /**
- * Check if composer should output anything.
- *
- * @return string
- */
- private function isComposerSilenced(): string
- {
- return config('modules.composer.composer-output') === false ? ' --quiet' : '';
- }
-
- /**
- * @param Module $module
- */
- private function installRequires(Module $module): void
- {
- $packages = $module->getComposerAttr('require', []);
-
- $concatenatedPackages = '';
- foreach ($packages as $name => $version) {
- $concatenatedPackages .= "\"{$name}:{$version}\" ";
- }
-
- if (!empty($concatenatedPackages)) {
- $this->run("composer require {$concatenatedPackages}{$this->isComposerSilenced()}");
- }
- }
-
- /**
- * @param Module $module
- */
- private function installDevRequires(Module $module): void
- {
- $devPackages = $module->getComposerAttr('require-dev', []);
-
- $concatenatedPackages = '';
- foreach ($devPackages as $name => $version) {
- $concatenatedPackages .= "\"{$name}:{$version}\" ";
- }
-
- if (!empty($concatenatedPackages)) {
- $this->run("composer require --dev {$concatenatedPackages}{$this->isComposerSilenced()}");
- }
- }
-
- /**
- * @param Module $module
- */
- private function copyScriptsToMainComposerJson(Module $module): void
- {
- $scripts = $module->getComposerAttr('scripts', []);
-
- $composer = json_decode(file_get_contents(base_path('composer.json')), true);
-
- foreach ($scripts as $key => $script) {
- if (array_key_exists($key, $composer['scripts'])) {
- $composer['scripts'][$key] = array_unique(array_merge($composer['scripts'][$key], $script));
- continue;
- }
- $composer['scripts'] = array_merge($composer['scripts'], [$key => $script]);
- }
-
- file_put_contents(base_path('composer.json'), json_encode($composer, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
- }
-}
diff --git a/src/Providers/BootstrapServiceProvider.php b/src/Providers/BootstrapServiceProvider.php
deleted file mode 100755
index d0c7b32..0000000
--- a/src/Providers/BootstrapServiceProvider.php
+++ /dev/null
@@ -1,25 +0,0 @@
-app[RepositoryInterface::class]->register();
- }
-
- /**
- * Bootstrap any application services.
- */
- public function boot(): void
- {
- $this->app[RepositoryInterface::class]->boot();
- }
-}
diff --git a/src/Providers/ComposerServiceProvider.php b/src/Providers/ComposerServiceProvider.php
new file mode 100644
index 0000000..1d8ec10
--- /dev/null
+++ b/src/Providers/ComposerServiceProvider.php
@@ -0,0 +1,31 @@
+app->singleton(Composer::class, function (Application $app) {
+ return new Composer($app['files'], $app->basePath());
+ });
+ }
+
+ /**
+ * Get the services provided by the provider.
+ *
+ * @return array
+ */
+ public function provides(): array
+ {
+ return [Composer::class];
+ }
+}
diff --git a/src/Providers/ConsoleServiceProvider.php b/src/Providers/ConsoleServiceProvider.php
index 32baf5e..551ce58 100644
--- a/src/Providers/ConsoleServiceProvider.php
+++ b/src/Providers/ConsoleServiceProvider.php
@@ -10,15 +10,12 @@ class ConsoleServiceProvider extends ServiceProvider implements DeferrableProvid
{
/**
* The available commands
- * @var array
+ *
+ * @var array
*/
- protected $commands = [
+ protected array $commands = [
Commands\CacheClearCommand::class,
Commands\CacheCommand::class,
- Commands\DisableCommand::class,
- Commands\DumpCommand::class,
- Commands\EnableCommand::class,
- Commands\InstallCommand::class,
Commands\ListCommand::class,
Commands\MigrateCommand::class,
Commands\MigrateRefreshCommand::class,
@@ -26,14 +23,10 @@ class ConsoleServiceProvider extends ServiceProvider implements DeferrableProvid
Commands\MigrateRollbackCommand::class,
Commands\MigrateStatusCommand::class,
Commands\ModuleDeleteCommand::class,
- Commands\SeedCommand::class,
- Commands\SetupCommand::class,
- Commands\UnUseCommand::class,
- Commands\UpdateCommand::class,
- Commands\UseCommand::class,
+ Commands\StubPublishCommand::class,
+ Commands\SyncCommand::class,
Commands\Generators\ActionMakeCommand::class,
Commands\Generators\CommandMakeCommand::class,
- Commands\Generators\ComponentsMakeCommand::class,
Commands\Generators\ControllerMakeCommand::class,
Commands\Generators\DTOMakeCommand::class,
Commands\Generators\EventMakeCommand::class,
@@ -50,15 +43,18 @@ class ConsoleServiceProvider extends ServiceProvider implements DeferrableProvid
Commands\Generators\ObserverMakeCommand::class,
Commands\Generators\PolicyMakeCommand::class,
Commands\Generators\ProviderMakeCommand::class,
- Commands\Generators\RouteMakeCommand::class,
Commands\Generators\QueryWizardMakeCommand::class,
Commands\Generators\RequestMakeCommand::class,
Commands\Generators\ResourceMakeCommand::class,
+ Commands\Generators\RouteMakeCommand::class,
Commands\Generators\RuleMakeCommand::class,
Commands\Generators\SeederMakeCommand::class,
Commands\Generators\TestMakeCommand::class,
];
+ /**
+ * Register commands
+ */
public function register(): void
{
if ($this->app->runningInConsole()) {
@@ -69,7 +65,7 @@ public function register(): void
/**
* Get the services provided by the provider.
*
- * @return array
+ * @return array
*/
public function provides(): array
{
diff --git a/src/Providers/ModulesRepositoryServiceProvider.php b/src/Providers/ModulesRepositoryServiceProvider.php
new file mode 100644
index 0000000..e8392f8
--- /dev/null
+++ b/src/Providers/ModulesRepositoryServiceProvider.php
@@ -0,0 +1,50 @@
+app->singleton(ModulesRepository::class, function (Application $app) {
+ return new ModulesRepository(
+ filesystem: $app['files'],
+ composer: $app[Composer::class],
+ modulesPath: $app['config']->get('modules.path'),
+ basePath: $app->basePath(),
+ modulesManifestPath: $app['config']->get('modules.cache.enabled')
+ ? $app->bootstrapPath('cache/laraneat-modules.php')
+ : null
+ );
+ });
+
+ $this->app->singleton(ModuleConfigWriter::class, function (Application $app) {
+ return new ModuleConfigWriter(
+ modulesRepository: $app[ModulesRepository::class],
+ );
+ });
+ }
+
+ /**
+ * Get the services provided by the provider.
+ *
+ * @return array
+ */
+ public function provides(): array
+ {
+ return [
+ ModulesRepository::class,
+ ModuleConfigWriter::class,
+ ];
+ }
+}
diff --git a/src/Providers/ModulesServiceProvider.php b/src/Providers/ModulesServiceProvider.php
new file mode 100755
index 0000000..1e62181
--- /dev/null
+++ b/src/Providers/ModulesServiceProvider.php
@@ -0,0 +1,28 @@
+mergeConfigFrom(__DIR__ . '/../../config/config.php', 'modules');
+ }
+
+ /**
+ * Bootstrap any application services.
+ */
+ public function boot(): void
+ {
+ if (app()->runningInConsole()) {
+ $this->publishes([
+ __DIR__ . '/../../config/config.php' => config_path('modules.php'),
+ ], 'config');
+ }
+ }
+}
diff --git a/src/Support/Composer.php b/src/Support/Composer.php
new file mode 100644
index 0000000..8819813
--- /dev/null
+++ b/src/Support/Composer.php
@@ -0,0 +1,43 @@
+ $packages
+ * @param bool $dev
+ * @param Closure|OutputInterface|null $output
+ * @param string|null $composerBinary
+ * @return bool
+ */
+ public function updatePackages(
+ array $packages,
+ bool $dev = false,
+ Closure|OutputInterface $output = null,
+ ?string $composerBinary = null
+ ): bool {
+ $command = collect([
+ ...$this->findComposer($composerBinary),
+ 'update',
+ ...$packages,
+ ])
+ ->when($dev, function ($command) {
+ $command->push('--dev');
+ })->all();
+
+ return 0 === $this->getProcess($command, ['COMPOSER_MEMORY_LIMIT' => '-1'])
+ ->run(
+ $output instanceof OutputInterface
+ ? function ($type, $line) use ($output) {
+ $output->write(' '.$line);
+ } : $output
+ );
+ }
+}
diff --git a/src/Support/ComposerJsonFile.php b/src/Support/ComposerJsonFile.php
new file mode 100644
index 0000000..f6aa7ba
--- /dev/null
+++ b/src/Support/ComposerJsonFile.php
@@ -0,0 +1,149 @@
+composerJsonHandler = new JsonFile($filePath);
+ }
+
+ public static function create(
+ string $filePath
+ ): static {
+ return new static($filePath);
+ }
+
+ /**
+ * Get an item from a json content using "dot" notation.
+ *
+ * @param string $key
+ * @param mixed $default
+ * @return mixed
+ */
+ public function get(string $key, mixed $default = null): mixed
+ {
+ return Arr::get($this->read(), $key, $default);
+ }
+
+ /**
+ * Set JSON content item to a given value using "dot" notation.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return $this
+ */
+ public function set(string $key, mixed $value): static
+ {
+ $this->read();
+ Arr::set($this->jsonContent, $key, $value);
+
+ return $this;
+ }
+
+ public function addModule(string $modulePackageName, string $moduleRelativePath): static
+ {
+ $this->addPathRepository(dirname($moduleRelativePath));
+
+ $packages = $this->get('require');
+
+ if (! isset($packages[$modulePackageName])) {
+ $packages[$modulePackageName] = '*';
+ $this->set('require', $this->sortPackages($packages));
+ }
+
+ return $this;
+ }
+
+ public function addPathRepository(string $path, array $options = ['symlink' => true]): static
+ {
+ $path = Str::finish(GeneratorHelper::normalizePath($path, true), '/*');
+
+ $repositories = $this->get('repositories', []);
+ $repositoryAlreadyExists = collect($repositories)
+ ->contains(fn ($repository) => $repository['url'] === $path);
+
+ if ($repositoryAlreadyExists) {
+ return $this;
+ }
+
+ $repositories[] = [
+ 'type' => 'path',
+ 'url' => $path,
+ 'options' => $options,
+ ];
+
+ $this->set('repositories', $repositories);
+
+ return $this;
+ }
+
+ /**
+ * Save the JSON content to a file
+ *
+ * @throws \Exception
+ */
+ public function save(int $flags = JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE): void
+ {
+ if ($this->jsonContent !== null) {
+ $this->composerJsonHandler->write($this->jsonContent, $flags);
+ }
+ }
+
+ protected function read(): array
+ {
+ if ($this->jsonContent !== null) {
+ return $this->jsonContent;
+ }
+
+ return $this->jsonContent = $this->composerJsonHandler->read();
+ }
+
+ /**
+ * @param array $packages
+ * @return array
+ */
+ protected function sortPackages(array $packages): array
+ {
+ $prefix = fn ($requirement)
+ => preg_replace(
+ [
+ '/^php$/',
+ '/^hhvm-/',
+ '/^ext-/',
+ '/^lib-/',
+ '/^\D/',
+ '/^(?!php$|hhvm-|ext-|lib-)/',
+ ],
+ [
+ '0-$0',
+ '1-$0',
+ '2-$0',
+ '3-$0',
+ '4-$0',
+ '5-$0',
+ ],
+ $requirement
+ );
+
+ uksort($packages, function ($a, $b) use ($prefix) {
+ return strnatcmp($prefix($a), $prefix($b));
+ });
+
+ return $packages;
+ }
+}
diff --git a/src/Support/Concerns/CanLoadRoutesFromDirectory.php b/src/Support/Concerns/CanLoadRoutesFromDirectory.php
new file mode 100644
index 0000000..4a65ce1
--- /dev/null
+++ b/src/Support/Concerns/CanLoadRoutesFromDirectory.php
@@ -0,0 +1,53 @@
+loadRoutesFromDirectory(
+ $nestedDirectory,
+ $directoryRoutePrefix,
+ $generateRoutePrefixesByNestedDirectories
+ );
+ }
+
+ /** @var SplFileInfo[] $files */
+ $files = Arr::sort(File::files($directory), function (SplFileInfo $file) {
+ return $file->getFilename();
+ });
+
+ Route::prefix($routePrefix)->group(function () use ($files) {
+ foreach ($files as $file) {
+ require $file->getPathname();
+ }
+ });
+ }
+}
diff --git a/src/Traits/SeederLoaderTrait.php b/src/Support/Concerns/CanRunModuleSeeders.php
similarity index 91%
rename from src/Traits/SeederLoaderTrait.php
rename to src/Support/Concerns/CanRunModuleSeeders.php
index 6a5fbd3..022f763 100644
--- a/src/Traits/SeederLoaderTrait.php
+++ b/src/Support/Concerns/CanRunModuleSeeders.php
@@ -1,12 +1,13 @@
getFullPath($module);
+ $moduleSeedersPath = GeneratorHelper::component(ModuleComponentType::Seeder)->getFullPath($module);
$paths = [$moduleSeedersPath];
- if (!empty($subdirectories)) {
+ if (! empty($subdirectories)) {
$paths += array_map(
static fn ($subdirectory)
=> rtrim($moduleSeedersPath, '/') . '/' . ltrim($subdirectory, '/'),
@@ -109,15 +110,17 @@ protected function getClassNamespaceFromFile(string $filePathName): ?string
if ($tokens[$i] === ';') {
$namespace_ok = true;
$namespace = trim($namespace);
+
break;
}
$namespace .= is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i];
}
+
break;
}
$i++;
}
- if (!$namespace_ok) {
+ if (! $namespace_ok) {
return null;
}
diff --git a/src/Support/Concerns/InteractsWithTestUser.php b/src/Support/Concerns/InteractsWithTestUser.php
new file mode 100644
index 0000000..c044c0a
--- /dev/null
+++ b/src/Support/Concerns/InteractsWithTestUser.php
@@ -0,0 +1,186 @@
+|null
+ */
+ protected ?string $testUserClass = null;
+
+ /**
+ * Roles and permissions, to be attached on the user by default
+ *
+ * @var array{permissions?: string|array, roles?:string|array}
+ */
+ protected array $testUserAccess = [
+ 'permissions' => '',
+ 'roles' => '',
+ ];
+
+ protected ?string $testUserGuard = null;
+
+ /**
+ * Create a test user without access and make him logged into the application.
+ * Same as `besTestUser()` but always overrides the user $access
+ * (roles and permissions) with null. So the user can be used to test
+ * if unauthorized user tried to access your protected endpoint.
+ *
+ * @param array|null $userDetails
+ * @param string|null $guard
+ *
+ * @return $this
+ */
+ public function beTestUserWithoutAccess(?array $userDetails = null, ?string $guard = null): static
+ {
+ return $this->actingAsTestUserWithoutAccess($userDetails, $guard);
+ }
+
+ /**
+ * Create a test user and make him logged into the application.
+ *
+ * @param array|null $userDetails
+ * @param array{permissions?: string|array, roles?:string|array}|null $access
+ * @param string|null $guard
+ *
+ * @return $this
+ */
+ public function beTestUser(?array $userDetails = null, ?array $access = null, ?string $guard = null): static
+ {
+ return $this->actingAsTestUser($userDetails, $access, $guard);
+ }
+
+ /**
+ * Create a test user without access and make him logged into the application.
+ * Same as `actingAsTestUser()` but always overrides the user $access
+ * (roles and permissions) with null. So the user can be used to test
+ * if unauthorized user tried to access your protected endpoint.
+ *
+ * @param array|null $userDetails
+ * @param string|null $guard
+ *
+ * @return $this
+ */
+ public function actingAsTestUserWithoutAccess(?array $userDetails = null, ?string $guard = null): static
+ {
+ return $this->actingAs(
+ $this->createTestUserWithoutAccess($userDetails),
+ $guard ?? $this->testUserGuard
+ );
+ }
+
+ /**
+ * Create a test user and make him logged into the application.
+ *
+ * @param array|null $userDetails
+ * @param array{permissions?: string|array, roles?:string|array}|null $access
+ * @param string|null $guard
+ *
+ * @return $this
+ */
+ public function actingAsTestUser(?array $userDetails = null, ?array $access = null, ?string $guard = null): static
+ {
+ return $this->actingAs(
+ $this->createTestUser($userDetails, $access),
+ $guard ?? $this->testUserGuard
+ );
+ }
+
+ /**
+ * Create test user without access.
+ * Same as `createTestUser()` but always overrides the user $access
+ * (roles and permissions) with null. So the user can be used to test
+ * if unauthorized user tried to access your protected endpoint.
+ *
+ * @param array|null $userDetails
+ * @return U
+ */
+ public function createTestUserWithoutAccess(?array $userDetails = null): UserContract
+ {
+ return $this->createTestUser($userDetails, [
+ 'permissions' => null,
+ 'roles' => null,
+ ]);
+ }
+
+ /**
+ * Create test user.
+ * By default, Users will be given the Roles and Permissions found in the class
+ * `$access` property. But the $access parameter can be used to override the
+ * defined roles and permissions in the `$access` property of your class.
+ *
+ * @param array|null $userDetails
+ * @param array{permissions?: string|array, roles?:string|array}|null $access
+ * @return U
+ */
+ public function createTestUser(?array $userDetails = null, ?array $access = null): UserContract
+ {
+ $this->testUserClass = $this->testUserClass ?? config('modules.user_model');
+
+ if (! $this->testUserClass) {
+ throw new LogicException("User class was not provided!");
+ }
+
+ return $this->setupTestUserAccess(
+ $this->factoryCreateUser($userDetails),
+ $access
+ );
+ }
+
+ /**
+ * @param array|null $userDetails
+ * @return U
+ */
+ private function factoryCreateUser(?array $userDetails = null): UserContract
+ {
+ if (! method_exists($this->testUserClass, 'factory')) {
+ throw new LogicException("class `$this->testUserClass` does not have method `factory()`");
+ }
+
+ return $this->testUserClass::factory()->create($this->prepareUserDetails($userDetails));
+ }
+
+ private function prepareUserDetails(?array $userDetails = null): array
+ {
+ $defaultUserDetails = [
+ 'name' => 'Testing user',
+ 'email' => 'testing@test.com',
+ 'password' => 'testing-password',
+ ];
+ $userDetails = $userDetails ? array_merge($defaultUserDetails, $userDetails) : $defaultUserDetails;
+
+ $userDetails['password'] = Hash::make($userDetails['password']);
+
+ return $userDetails;
+ }
+
+ private function setupTestUserAccess(UserContract $user, ?array $access = null): UserContract
+ {
+ $access = $access ?: $this->testUserAccess;
+
+ if ($access['permissions'] ?? false) {
+ if (! method_exists($user, 'givePermissionTo')) {
+ throw new LogicException("user instance does not have method `givePermissionTo()`, make sure the user class uses `spatie/laravel-permission`");
+ }
+ $user->givePermissionTo($access['permissions']);
+ }
+
+ if ($access['roles'] ?? false) {
+ if (! method_exists($user, 'assignRole')) {
+ throw new LogicException("user instance does not have method `assignRole()`, make sure the user class uses `spatie/laravel-permission`");
+ }
+ $user->assignRole($access['roles']);
+ }
+
+ return $user;
+ }
+}
diff --git a/src/Traits/ResponseHelpersTrait.php b/src/Support/Concerns/WithJsonResponseHelpers.php
similarity index 93%
rename from src/Traits/ResponseHelpersTrait.php
rename to src/Support/Concerns/WithJsonResponseHelpers.php
index 40e47f1..86ab197 100644
--- a/src/Traits/ResponseHelpersTrait.php
+++ b/src/Support/Concerns/WithJsonResponseHelpers.php
@@ -1,10 +1,10 @@
getScanPaths()
+ * @method static $this addScanPath(string|string[] $scanPaths)
+ * @method static array buildModulesManifest()
+ * @method static bool pruneModulesManifest()
+ * @method static array getModules()
+ * @method static array getPackagesToIgnore()
+ * @method static bool has(string $modulePackageName)
+ * @method static int count()
+ * @method static Module|null find(string $modulePackageName)
+ * @method static Module findOrFail(string $modulePackageName)
+ * @method static array filterByName(string $moduleName)
+ * @method static array filterByNameOrFail(string $moduleName)
+ * @method static bool delete(string $modulePackageName)
+ * @method static void syncWithComposer(\Closure|OutputInterface $output = null)
+ * @method static array toArray()
+ *
+ * @see \Laraneat\Modules\ModulesRepository
+ */
+class Modules extends Facade
+{
+ /**
+ * Get the registered name of the component.
+ */
+ protected static function getFacadeAccessor(): string
+ {
+ return ModulesRepository::class;
+ }
+}
diff --git a/src/Support/Generator/GeneratorHelper.php b/src/Support/Generator/GeneratorHelper.php
index 8665190..dc60a4c 100755
--- a/src/Support/Generator/GeneratorHelper.php
+++ b/src/Support/Generator/GeneratorHelper.php
@@ -2,8 +2,9 @@
namespace Laraneat\Modules\Support\Generator;
-use Laraneat\Modules\Exceptions\ModuleNotFoundException;
-use Laraneat\Modules\Facades\Modules;
+use Illuminate\Support\Str;
+use Laraneat\Modules\Enums\ModuleComponentType;
+use Laraneat\Modules\Exceptions\InvalidConfigValue;
use Laraneat\Modules\Module;
class GeneratorHelper
@@ -11,134 +12,203 @@ class GeneratorHelper
/**
* Get generator modules path
*
- * @return string
+ * @throws InvalidConfigValue
*/
- public static function path(): string
+ public static function getBasePath(): string
{
- return rtrim(config("modules.generator.path"), '/');
+ $generatorPath = config('modules.path');
+
+ if (! $generatorPath) {
+ throw InvalidConfigValue::makeForNullValue('modules.path');
+ }
+
+ return self::normalizePath($generatorPath, true);
}
/**
* Get generator modules namespace
*
- * @return string
+ * @throws InvalidConfigValue
*/
- public static function namespace(): string
+ public static function getBaseNamespace(): string
{
- return self::formatNamespace(config("modules.generator.namespace"));
+ $generatorNamespace = config('modules.namespace');
+
+ if (! $generatorNamespace) {
+ throw InvalidConfigValue::makeForNullValue('modules.namespace');
+ }
+
+ return self::normalizeNamespace($generatorNamespace);
}
/**
* Get custom stubs path
- *
- * @return string
*/
- public static function customStubsPath(): string
+ public static function getCustomStubsPath(): ?string
{
- return rtrim(config("modules.generator.custom_stubs"), '/');
+ $customStubsPath = config('modules.custom_stubs', base_path('/stubs/modules'));
+
+ return $customStubsPath ? self::normalizePath($customStubsPath, true) : null;
}
/**
- * Get user model
+ * Get user model class
*
- * @return string
+ * @return class-string|null
*/
- public static function userModel(): string
+ public static function getUserModelClass(): ?string
{
- return self::formatNamespace(config("modules.generator.user_model"));
+ $userModelClass = config('modules.user_model');
+
+ return $userModelClass && is_string($userModelClass) ? self::normalizeNamespace($userModelClass) : null;
}
/**
- * Get "create permission" action
+ * Get "create permission" action class
*
- * @return string
+ * @return class-string|null
*/
- public static function createPermissionAction(): string
+ public static function getCreatePermissionActionClass(): ?string
{
- return self::formatNamespace(config("modules.generator.create_permission.action"));
+ $createPermissionActionClass = config('modules.create_permission.action');
+
+ return $createPermissionActionClass && is_string($createPermissionActionClass)
+ ? self::normalizeNamespace($createPermissionActionClass)
+ : null;
}
/**
- * Get "create permission" DTO
+ * Get "create permission" DTO class
*
- * @return string
+ * @return class-string|null
*/
- public static function createPermissionDTO(): string
+ public static function getCreatePermissionDTOClass(): ?string
{
- return self::formatNamespace(config("modules.generator.create_permission.dto"));
+ $createPermissionDTOClass = config('modules.create_permission.dto');
+
+ return $createPermissionDTOClass && is_string($createPermissionDTOClass)
+ ? self::normalizeNamespace($createPermissionDTOClass)
+ : null;
}
/**
* Get component config
*
- * @param string $componentType
- *
- * @return GeneratorPath
+ * @throws InvalidConfigValue
*/
- public static function component(string $componentType): GeneratorPath
+ public static function component(ModuleComponentType $componentType): GeneratorPath
{
- return new GeneratorPath(config("modules.generator.components.$componentType"));
+ $configPath = "modules.components.{$componentType->value}";
+ $generatorComponent = config($configPath);
+
+ if (! is_array($generatorComponent) || empty($generatorComponent['path'])) {
+ throw InvalidConfigValue::make($configPath);
+ };
+
+ return new GeneratorPath($generatorComponent);
}
/**
* Get module path
*
- * @param Module|string $module
- * @param string|null $extraPath
- * @return string
+ * @throws InvalidConfigValue
*/
- public static function modulePath(Module|string $module, ?string $extraPath = null): string
+ public static function makeModulePath(Module|string $moduleOrName, ?string $subPath = null): ?string
{
- try {
- $modulePath = Modules::getModulePath($module);
- } catch (ModuleNotFoundException $e) {
- $modulesPath = self::path();
- $modulePart = self::formatPath($module);
- $modulePath = $modulePart ? $modulesPath . '/' . $modulePart : $modulePart;
+ if ($moduleOrName instanceof Module) {
+ return $moduleOrName->subPath($subPath);
+ }
+
+ $modulePart = self::normalizePath($moduleOrName);
+
+ if (! $modulePart) {
+ return null;
}
- return $extraPath ? $modulePath . '/' . self::formatPath($extraPath) : $modulePath;
+ $modulePath = self::getBasePath() . '/' . $modulePart;
+
+ return $subPath ? $modulePath . '/' . self::normalizePath($subPath) : $modulePath;
}
/**
* Get module namespace
*
- * @param Module|string $module
- * @param string|null $extraNamespace
- * @return string
+ * @throws InvalidConfigValue
*/
- public static function moduleNamespace(Module|string $module, ?string $extraNamespace = null): string
+ public static function makeModuleNamespace(Module|string $moduleOrName, ?string $subNamespace = null): ?string
{
- try {
- $moduleNamespace = Modules::getModuleNamespace($module);
- } catch (ModuleNotFoundException $e) {
- $modulesNamespace = self::namespace();
- $modulePart = self::formatNamespace($module);
- $moduleNamespace = $modulePart ? $modulesNamespace . '\\' . $modulePart : $modulePart;
+ if ($moduleOrName instanceof Module) {
+ return $moduleOrName->subNamespace($subNamespace);
}
- return $extraNamespace ? $moduleNamespace . '\\' . self::formatNamespace($extraNamespace) : $moduleNamespace;
+ $modulePart = self::normalizeNamespace(Str::studly($moduleOrName));
+
+ if (! $modulePart) {
+ return null;
+ }
+
+ $moduleNamespace = self::getBaseNamespace() . '\\' . $modulePart;
+
+ return $subNamespace ? $moduleNamespace . '\\' . self::normalizeNamespace($subNamespace) : $moduleNamespace;
}
/**
- * Format path (normalize slashes)
- *
- * @param string $path
- * @return string
+ * Make relative path or returns null
*/
- private static function formatPath(string $path): string
+ public static function makeRelativePath(string $from, string $to): ?string
{
- return trim(str_replace('\\', '/', $path), '/');
+ $from = static::normalizePath($from, true);
+ $to = static::normalizePath($to, true);
+
+ if ($from === $to) {
+ return '';
+ }
+
+ $fromSegments = explode('/', $from);
+ $toSegments = explode('/', $to);
+
+ $diffStartIndex = null;
+ $fromSegmentsCount = count($fromSegments);
+ $toSegmentsCount = count($toSegments);
+ $segmentsCount = max($fromSegmentsCount, $toSegmentsCount);
+ for ($i = 0; $i < $segmentsCount; $i++) {
+ if (! isset($fromSegments[$i], $toSegments[$i]) || $fromSegments[$i] !== $toSegments[$i]) {
+ if ($i === 0 || $i === 1 && ! $fromSegments[0]) {
+ return null;
+ }
+ $diffStartIndex = $i;
+
+ break;
+ }
+ }
+
+ $relativePath = Str::repeat('../', $fromSegmentsCount - $diffStartIndex)
+ . join('/', array_slice($toSegments, $diffStartIndex));
+
+ return rtrim($relativePath, '/');
}
/**
- * Format namespace (normalize slashes)
- *
- * @param string $namespace
- * @return string
+ * Normalize path to use only forward slash and trim slashes
*/
- private static function formatNamespace(string $namespace): string
+ public static function normalizePath(string $path, $useRtrim = false): string
{
- return trim(str_replace('/', '\\', $namespace), '\\');
+ $path = str_replace('\\', '/', $path);
+
+ return $useRtrim && Str::startsWith($path, '/')
+ ? '/' . trim($path, '/')
+ : trim($path, '/');
+ }
+
+ /**
+ * Normalize namespace to use only backslash and trim slashes
+ */
+ public static function normalizeNamespace(string $namespace, $useRtrim = false): string
+ {
+ $namespace = str_replace('/', '\\', $namespace);
+
+ return $useRtrim && Str::startsWith($namespace, '\\')
+ ? '\\' . trim($namespace, '\\')
+ : trim($namespace, '\\');
}
}
diff --git a/src/Support/Generator/GeneratorPath.php b/src/Support/Generator/GeneratorPath.php
index 6aefc4c..f522389 100755
--- a/src/Support/Generator/GeneratorPath.php
+++ b/src/Support/Generator/GeneratorPath.php
@@ -6,29 +6,13 @@
class GeneratorPath
{
- private string $path;
- private string $namespace;
- private bool $generate;
- private bool $gitkeep;
+ protected string $path;
+ protected string $namespace;
- /**
- * @param array|bool|string $config
- */
- public function __construct($config)
+ public function __construct(array $config)
{
- if (!is_array($config)) {
- $config = [
- 'path' => (string) $config,
- 'generate' => (bool) $config
- ];
- }
-
- $this->path = $this->formatPath((string) $config['path']);
- $this->namespace = $this->formatNamespace(
- $this->convertPathToNamespace((string) ($config['namespace'] ?? $this->path))
- );
- $this->generate = (bool) ($config['generate'] ?? true);
- $this->gitkeep = (bool) ($config['gitkeep'] ?? false);
+ $this->path = GeneratorHelper::normalizePath((string) $config['path']);
+ $this->namespace = GeneratorHelper::normalizeNamespace($config['namespace'] ?? $this->path);
}
public function getPath(): string
@@ -38,7 +22,7 @@ public function getPath(): string
public function getFullPath(Module|string $module): string
{
- return GeneratorHelper::modulePath($module, $this->path);
+ return GeneratorHelper::makeModulePath($module, $this->path);
}
public function getNamespace(): string
@@ -48,36 +32,6 @@ public function getNamespace(): string
public function getFullNamespace(Module|string $module): string
{
- return GeneratorHelper::moduleNamespace($module, $this->namespace);
- }
-
- public function generate(): bool
- {
- return $this->generate;
- }
-
- public function withGitKeep(): bool
- {
- return $this->gitkeep;
- }
-
- protected function formatPath(string $path): string
- {
- return trim($path, '/');
- }
-
- protected function formatNamespace(string $namespace): string
- {
- return trim($namespace, '\\');
- }
-
- protected function convertPathToNamespace(string $path): string
- {
- return str_replace('/', '\\', $path);
- }
-
- protected function convertNamespaceToPath(string $path): string
- {
- return str_replace('\\', '/', $path);
+ return GeneratorHelper::makeModuleNamespace($module, $this->namespace);
}
}
diff --git a/src/Support/Stub.php b/src/Support/Generator/Stub.php
similarity index 62%
rename from src/Support/Stub.php
rename to src/Support/Generator/Stub.php
index e5c414c..523ca75 100755
--- a/src/Support/Stub.php
+++ b/src/Support/Generator/Stub.php
@@ -1,28 +1,24 @@
*/
protected array $replaces = [];
/**
* @param string $path
- * @param array $replaces
+ * @param array $replaces
*/
public function __construct(string $path, array $replaces = [])
{
@@ -34,11 +30,11 @@ public function __construct(string $path, array $replaces = [])
* Create new self instance.
*
* @param string $path
- * @param array $replaces
+ * @param array $replaces
*
- * @return static
+ * @return Stub
*/
- public static function create(string $path, array $replaces = [])
+ public static function create(string $path, array $replaces = []): Stub
{
return new static($path, $replaces);
}
@@ -50,7 +46,7 @@ public static function create(string $path, array $replaces = [])
*
* @return $this
*/
- public function setPath(string $path)
+ public function setPath(string $path): static
{
$this->path = $path;
@@ -59,72 +55,27 @@ public function setPath(string $path)
/**
* Get stub path.
- *
- * @return string
*/
public function getPath(): string
{
- $customStubsFolderPath = GeneratorHelper::customStubsPath();
+ $customStubsFolderPath = GeneratorHelper::getCustomStubsPath();
$customStubFilePath = $customStubsFolderPath . '/' . ltrim($this->path, '/');
if (file_exists($customStubFilePath)) {
return $customStubFilePath;
}
- return __DIR__ . '/../Commands/Generators/stubs/' . ltrim($this->path, '/');
- }
-
- /**
- * Get stub contents.
- *
- * @return string
- */
- public function getContents(): string
- {
- $contents = file_get_contents($this->getPath());
-
- foreach ($this->replaces as $search => $replace) {
- $contents = str_replace(
- ['{{' . $search . '}}', '{{ ' . $search . ' }}'],
- $replace,
- $contents
- );
- }
-
- return $contents;
- }
-
- /**
- * Get stub contents.
- *
- * @return string
- */
- public function render(): string
- {
- return $this->getContents();
- }
-
- /**
- * Save stub to specific path.
- *
- * @param string $path
- * @param string $filename
- *
- * @return int|false
- */
- public function saveTo(string $path, string $filename)
- {
- return file_put_contents($path . '/' . $filename, $this->getContents());
+ return __DIR__ . '/../../Commands/Generators/stubs/' . ltrim($this->path, '/');
}
/**
* Set replacements array.
*
- * @param array $replaces
+ * @param array $replaces
*
* @return $this
*/
- public function replace(array $replaces = [])
+ public function setReplaces(array $replaces = []): static
{
$this->replaces = $replaces;
@@ -134,17 +85,33 @@ public function replace(array $replaces = [])
/**
* Get replacements.
*
- * @return array
+ * @return array
*/
public function getReplaces(): array
{
return $this->replaces;
}
+ /**
+ * Render stub contents.
+ */
+ public function render(): string
+ {
+ $contents = file_get_contents($this->getPath());
+
+ foreach ($this->replaces as $search => $replace) {
+ $contents = str_replace(
+ ['{{' . $search . '}}', '{{ ' . $search . ' }}'],
+ $replace,
+ $contents
+ );
+ }
+
+ return $contents;
+ }
+
/**
* Handle magic method __toString.
- *
- * @return string
*/
public function __toString()
{
diff --git a/src/Support/Migrations/NameParser.php b/src/Support/Migrations/NameParser.php
index 6886d32..84c656f 100755
--- a/src/Support/Migrations/NameParser.php
+++ b/src/Support/Migrations/NameParser.php
@@ -6,22 +6,16 @@ class NameParser
{
/**
* The migration name.
- *
- * @var string
*/
protected string $name;
/**
* The array data.
- *
- * @var array
*/
protected array $data = [];
/**
* The available schema actions.
- *
- * @var array
*/
protected array $actions = [
'create' => [
@@ -42,8 +36,6 @@ class NameParser
/**
* The constructor.
- *
- * @param string $name
*/
public function __construct(string $name)
{
@@ -53,8 +45,6 @@ public function __construct(string $name)
/**
* Get original migration name.
- *
- * @return string
*/
public function getOriginalName(): string
{
@@ -63,8 +53,6 @@ public function getOriginalName(): string
/**
* Get schema type or action.
- *
- * @return string
*/
public function getAction(): string
{
@@ -73,8 +61,6 @@ public function getAction(): string
/**
* Get the table will be used.
- *
- * @return string|null
*/
public function getTableName(): ?string
{
@@ -85,8 +71,6 @@ public function getTableName(): ?string
/**
* Get matches data from regex.
- *
- * @return array
*/
public function getMatches(): array
{
@@ -97,35 +81,18 @@ public function getMatches(): array
/**
* Get name pattern.
- *
- * @return string
*/
public function getPattern(): string
{
- switch ($action = $this->getAction()) {
- case 'add':
- case 'append':
- case 'update':
- case 'insert':
- return "/{$action}_(.*)_to_(.*)_table/";
- break;
-
- case 'delete':
- case 'remove':
- case 'alter':
- return "/{$action}_(.*)_from_(.*)_table/";
- break;
-
- default:
- return "/{$action}_(.*)_table/";
- break;
- }
+ return match ($action = $this->getAction()) {
+ 'add', 'append', 'update', 'insert' => "/{$action}_(.*)_to_(.*)_table/",
+ 'delete', 'remove', 'alter' => "/{$action}_(.*)_from_(.*)_table/",
+ default => "/{$action}_(.*)_table/",
+ };
}
/**
* Fetch the migration name to an array data.
- *
- * @return array
*/
protected function fetchData(): array
{
@@ -134,8 +101,6 @@ protected function fetchData(): array
/**
* Get the array data.
- *
- * @return array
*/
public function getData(): array
{
@@ -144,20 +109,14 @@ public function getData(): array
/**
* Determine whether the given type is same with the current schema action or type.
- *
- * @param $type
- *
- * @return bool
*/
- public function is($type): bool
+ public function is(string $type): bool
{
return $type === $this->getAction();
}
/**
* Determine whether the current schema action is a adding action.
- *
- * @return bool
*/
public function isAdd(): bool
{
@@ -166,8 +125,6 @@ public function isAdd(): bool
/**
* Determine whether the current schema action is a deleting action.
- *
- * @return bool
*/
public function isDelete(): bool
{
@@ -176,8 +133,6 @@ public function isDelete(): bool
/**
* Determine whether the current schema action is a creating action.
- *
- * @return bool
*/
public function isCreate(): bool
{
diff --git a/src/Support/Migrations/SchemaParser.php b/src/Support/Migrations/SchemaParser.php
index c6d9939..514ab59 100755
--- a/src/Support/Migrations/SchemaParser.php
+++ b/src/Support/Migrations/SchemaParser.php
@@ -10,8 +10,6 @@ class SchemaParser implements Arrayable
{
/**
* The array of custom attributes.
- *
- * @var array
*/
protected array $customAttributes = [
'remember_token' => 'rememberToken()',
@@ -20,15 +18,11 @@ class SchemaParser implements Arrayable
/**
* The migration schema.
- *
- * @var string|null
*/
protected ?string $schema;
/**
* The relationship keys.
- *
- * @var array
*/
protected array $relationshipKeys = [
'belongsTo',
@@ -36,8 +30,6 @@ class SchemaParser implements Arrayable
/**
* Create new instance.
- *
- * @param string|null $schema
*/
public function __construct(?string $schema = null)
{
@@ -46,10 +38,6 @@ public function __construct(?string $schema = null)
/**
* Parse a string to array of formatted schema.
- *
- * @param string|null $schema
- *
- * @return array
*/
public function parse(?string $schema): array
{
@@ -70,8 +58,6 @@ public function parse(?string $schema): array
/**
* Get array of schema.
- *
- * @return array
*/
public function getSchemas(): array
{
@@ -84,8 +70,6 @@ public function getSchemas(): array
/**
* Convert string migration to array.
- *
- * @return array
*/
public function toArray(): array
{
@@ -94,8 +78,6 @@ public function toArray(): array
/**
* Render the migration to formatted script.
- *
- * @return string
*/
public function render(): string
{
@@ -110,8 +92,6 @@ public function render(): string
/**
* Render up migration fields.
- *
- * @return string
*/
public function up(): string
{
@@ -120,15 +100,12 @@ public function up(): string
/**
* Render down migration fields.
- *
- * @return string
*/
public function down(): string
{
$results = '';
foreach ($this->toArray() as $column => $attributes) {
- $attributes = [head($attributes)];
$results .= $this->createField($column, $attributes, 'remove');
}
@@ -137,21 +114,22 @@ public function down(): string
/**
* Create field.
- *
- * @param string $column
- * @param array $attributes
- * @param string $type
- *
- * @return string
*/
public function createField(string $column, array $attributes, string $type = 'add'): string
{
$results = "\t\t\t" . '$table';
- foreach ($attributes as $key => $field) {
- if (in_array($column, $this->relationshipKeys, true)) {
- $results .= $this->addRelationColumn($key, $field, $column);
- } else {
+ if (in_array($column, $this->relationshipKeys, true)) {
+ if ($type === 'add') {
+ $results .= $this->addRelationColumn($attributes, $column);
+ } elseif ($type === 'remove') {
+ $results .= $this->removeRelationColumn($attributes, $column);
+ }
+ } else {
+ if ($type === 'remove') {
+ $attributes = [head($attributes)];
+ }
+ foreach ($attributes as $key => $field) {
$results .= $this->{"{$type}Column"}($key, $field, $column);
}
}
@@ -161,41 +139,45 @@ public function createField(string $column, array $attributes, string $type = 'a
/**
* Add relation column.
- *
- * @param int $key
- * @param string $field
- * @param string $column
- *
- * @return string
*/
- protected function addRelationColumn(int $key, string $field, string $column): string
+ protected function addRelationColumn(array $attributes, string $column): string
{
- if ($key === 0) {
- $relatedColumn = Str::snake(class_basename($field)) . '_id';
+ $result = '';
- return "->integer('{$relatedColumn}')->unsigned();" . PHP_EOL . "\t\t\t" . "\$table->foreign('{$relatedColumn}')";
- }
- if ($key === 1) {
- return "->references('{$field}')";
- }
- if ($key === 2) {
- return "->on('{$field}')";
+ foreach ($attributes as $key => $field) {
+ if ($key === 0) {
+ $relatedColumn = Str::snake(class_basename($field)) . '_id';
+ $result .= "->integer('$relatedColumn')->unsigned();" . PHP_EOL . "\t\t\t" . "\$table->foreign('$relatedColumn')";
+ } elseif ($key === 1) {
+ $result .= "->references('$field')";
+ } elseif ($key === 2) {
+ $result .= "->on('$field')";
+ } elseif (Str::contains($field, '(')) {
+ $result .= '->' . $field;
+ } else {
+ $result .= '->' . $field . '()';
+ }
}
- if (Str::contains($field, '(')) {
- return '->' . $field;
+
+ return $result;
+ }
+
+ /**
+ * Remove relation column.
+ */
+ protected function removeRelationColumn(array $attributes, string $column): string
+ {
+ if (! ($attributes[0] ?? null)) {
+ return "";
}
- return '->' . $field . '()';
+ $relatedColumn = Str::snake(class_basename($attributes[0])) . '_id';
+
+ return "->dropColumn('$relatedColumn');" . PHP_EOL . "\t\t\t" . "\$table->dropForeign(['$relatedColumn'])";
}
/**
* Format field to script.
- *
- * @param int $key
- * @param string $field
- * @param string $column
- *
- * @return string
*/
protected function addColumn(int $key, string $field, string $column): string
{
@@ -216,12 +198,6 @@ protected function addColumn(int $key, string $field, string $column): string
/**
* Format field to script.
- *
- * @param int $key
- * @param string $field
- * @param string $column
- *
- * @return string
*/
protected function removeColumn(int $key, string $field, string $column): string
{
@@ -234,10 +210,6 @@ protected function removeColumn(int $key, string $field, string $column): string
/**
* Get column name from schema.
- *
- * @param string $schema
- *
- * @return string
*/
public function getColumn(string $schema): string
{
@@ -246,11 +218,6 @@ public function getColumn(string $schema): string
/**
* Get column attributes.
- *
- * @param string $column
- * @param string $schema
- *
- * @return array
*/
public function getAttributes(string $column, string $schema): array
{
@@ -260,11 +227,7 @@ public function getAttributes(string $column, string $schema): array
}
/**
- * Determine whether the given column is exist in customAttributes array.
- *
- * @param string $column
- *
- * @return bool
+ * Determine whether the given column exists in the customAttributes array.
*/
public function hasCustomAttribute(string $column): bool
{
@@ -273,10 +236,6 @@ public function hasCustomAttribute(string $column): bool
/**
* Get custom attributes value.
- *
- * @param string $column
- *
- * @return array
*/
public function getCustomAttribute(string $column): array
{
diff --git a/src/Support/ModuleConfigWriter.php b/src/Support/ModuleConfigWriter.php
new file mode 100644
index 0000000..45c0825
--- /dev/null
+++ b/src/Support/ModuleConfigWriter.php
@@ -0,0 +1,96 @@
+ $providers
+ *
+ * @throws FileNotFoundException
+ */
+ public function updateProviders(Module $module, array $providers): void
+ {
+ $this->updateConfig($module, 'extra.laravel.providers', $providers);
+ }
+
+ /**
+ * Update module aliases in composer.json
+ *
+ * @param Module $module
+ * @param array $aliases
+ *
+ * @throws FileNotFoundException
+ */
+ public function updateAliases(Module $module, array $aliases): void
+ {
+ $this->updateConfig($module, 'extra.laravel.aliases', $aliases);
+ }
+
+ /**
+ * Add a provider to the module
+ *
+ * @param Module $module
+ * @param class-string $providerClass
+ *
+ * @throws FileNotFoundException
+ */
+ public function addProvider(Module $module, string $providerClass): void
+ {
+ $providers = $module->getProviders();
+
+ if (! in_array($providerClass, $providers, true)) {
+ $providers[] = $providerClass;
+ $this->updateProviders($module, $providers);
+ }
+ }
+
+ /**
+ * Add an alias to the module
+ *
+ * @param Module $module
+ * @param string $alias
+ * @param class-string $class
+ *
+ * @throws FileNotFoundException
+ */
+ public function addAlias(Module $module, string $alias, string $class): void
+ {
+ $aliases = $module->getAliases();
+
+ if (! isset($aliases[$alias]) || $aliases[$alias] !== $class) {
+ $aliases[$alias] = $class;
+ $this->updateAliases($module, $aliases);
+ }
+ }
+
+ /**
+ * Update a config value in module's composer.json
+ *
+ * @param Module $module
+ * @param string $key
+ * @param mixed $value
+ *
+ * @throws FileNotFoundException|\Exception
+ */
+ protected function updateConfig(Module $module, string $key, mixed $value): void
+ {
+ ComposerJsonFile::create($module->getPath() . '/composer.json')
+ ->set($key, $value)
+ ->save();
+
+ $this->modulesRepository->pruneModulesManifest();
+ }
+}
diff --git a/src/Support/ModuleServiceProvider.php b/src/Support/ModuleServiceProvider.php
new file mode 100644
index 0000000..70f3484
--- /dev/null
+++ b/src/Support/ModuleServiceProvider.php
@@ -0,0 +1,111 @@
+ $pathsByNamespace
+ *
+ * @throws ReflectionException
+ */
+ protected function loadCommandsFrom(
+ array $pathsByNamespace,
+ ): void {
+ $pathsByNamespace = array_unique(Arr::wrap($pathsByNamespace));
+ $pathsByNamespace = array_filter($pathsByNamespace, static function ($path) {
+ return is_dir($path);
+ });
+
+ if (empty($pathsByNamespace)) {
+ return;
+ }
+
+ foreach ($pathsByNamespace as $namespace => $path) {
+ foreach (Finder::create()->in($path)->files() as $file) {
+ $command = $this->commandClassFromFile($file, $path, $namespace);
+
+ if (
+ is_subclass_of($command, Command::class) &&
+ ! (new ReflectionClass($command))->isAbstract()
+ ) {
+ Artisan::starting(function ($artisan) use ($command) {
+ $artisan->resolve($command);
+ });
+ }
+ }
+ }
+ }
+
+ /**
+ * Extract the command class name from the given file path.
+ */
+ protected function commandClassFromFile(
+ SplFileInfo $file,
+ string $basePath,
+ string $baseNamespace
+ ): string {
+ return rtrim($baseNamespace, '\\') . '\\' . str_replace(
+ ['/', '.php'],
+ ['\\', ''],
+ Str::after($file->getRealPath(), realpath($basePath) . DIRECTORY_SEPARATOR)
+ );
+ }
+
+ /**
+ * Load files from directory
+ */
+ protected function loadFiles(string $directory): void
+ {
+ if (File::isDirectory($directory)) {
+ $files = File::files($directory);
+
+ foreach ($files as $file) {
+ require_once $file;
+ }
+ }
+ }
+
+ /**
+ * Load all files from directory
+ */
+ protected function loadAllFiles(string $directory): void
+ {
+ if (File::isDirectory($directory)) {
+ $files = File::allFiles($directory);
+
+ foreach ($files as $file) {
+ require_once $file;
+ }
+ }
+ }
+}
diff --git a/src/Traits/ConsoleHelpersTrait.php b/src/Traits/ConsoleHelpersTrait.php
deleted file mode 100644
index b326d33..0000000
--- a/src/Traits/ConsoleHelpersTrait.php
+++ /dev/null
@@ -1,136 +0,0 @@
-argument($key));
- }
-
- /**
- * Get trimmed option
- *
- * @param string $key
- *
- * @return string
- */
- protected function getTrimmedOption(string $key): string
- {
- return trim($this->option($key));
- }
-
- /**
- * Checks if the option is set (via CLI), otherwise asks the user for a value
- *
- * @param string $optionName
- * @param string $question
- * @param mixed $default
- * @param bool $required
- *
- * @return string
- */
- protected function getOptionOrAsk(string $optionName, string $question, $default = null, bool $required = false): string
- {
- $value = $this->getTrimmedOption($optionName);
-
- if ($value === '' || $value === null) {
- $value = trim($this->ask($question, $default));
- }
-
- if ($required && empty($value)) {
- throw new InvalidOptionException(
- sprintf('The "%s" option is required', $optionName)
- );
- }
-
- return $value;
- }
-
- /**
- * Checks if the option is set (via CLI), otherwise proposes choices to the user
- *
- * @param string $optionName
- * @param string $question
- * @param array $choices
- * @param mixed $default
- *
- * @return string
- */
- protected function getOptionOrChoice(string $optionName, string $question, array $choices, $default = null): string
- {
- $value = $this->getTrimmedOption($optionName);
-
- if ($value === '' || $value === null) {
- $value = trim($this->choice($question, $choices, $default));
- } elseif (!in_array(mb_strtolower($value), $choices, true)) {
- throw new InvalidOptionException(
- sprintf(
- 'Wrong "%s" option value provided. Value should be one of "%s".',
- $optionName,
- implode('" or "', $choices)
- )
- );
- }
-
- return $value;
- }
-
- /**
- * Get an option that is one of the valid values
- *
- * @param string $optionName
- * @param array $validValues
- *
- * @return string
- */
- protected function getOptionOneOf(string $optionName, array $validValues): string
- {
- $value = $this->getTrimmedOption($optionName);
-
- if (!in_array(mb_strtolower($value), $validValues, true)) {
- throw new InvalidOptionException(
- sprintf(
- 'Wrong "%s" option value provided. Value should be one of "%s".',
- $optionName,
- implode('" or "', $validValues)
- )
- );
- }
-
- return $value;
- }
-
- /**
- * Checks if the option is set (via CLI), otherwise, asks the user for confirmation
- *
- * @param string $optionName
- * @param string $question
- * @param bool $default
- *
- * @return bool
- */
- protected function getOptionOrConfirm(string $optionName, string $question, $default = false): bool
- {
- $value = $this->option($optionName);
-
- if ($value === null) {
- $value = $this->confirm($question, $default);
- }
-
- return (bool) $value;
- }
-}
diff --git a/src/Traits/ModuleCommandTrait.php b/src/Traits/ModuleCommandTrait.php
deleted file mode 100755
index ee2a280..0000000
--- a/src/Traits/ModuleCommandTrait.php
+++ /dev/null
@@ -1,24 +0,0 @@
-argument('module');
-
- return $moduleName ? Modules::findOrFail($moduleName) : Modules::getUsedNow();
- }
-}
diff --git a/src/Traits/ModuleProviderHelpersTrait.php b/src/Traits/ModuleProviderHelpersTrait.php
deleted file mode 100644
index b49c446..0000000
--- a/src/Traits/ModuleProviderHelpersTrait.php
+++ /dev/null
@@ -1,127 +0,0 @@
-app->getNamespace();
-
- foreach (Finder::create()->in($paths)->files() as $file) {
- $command = $this->commandClassFromFile($file, $namespace);
-
- if (
- is_subclass_of($command, Command::class) &&
- !(new ReflectionClass($command))->isAbstract()
- ) {
- Artisan::starting(function ($artisan) use ($command) {
- $artisan->resolve($command);
- });
- }
- }
- }
-
- /**
- * Extract the command class name from the given file path.
- *
- * @param \SplFileInfo $file
- * @param string $namespace
- * @return string
- */
- protected function commandClassFromFile(SplFileInfo $file, string $namespace): string
- {
- return $namespace . str_replace(
- ['/', '.php'],
- ['\\', ''],
- Str::after($file->getRealPath(), realpath(app_path()) . DIRECTORY_SEPARATOR)
- );
- }
-
- /**
- * Load files from directory
- *
- * @param string $directory
- *
- * @return void
- */
- protected function loadFiles(string $directory): void
- {
- if (File::isDirectory($directory)) {
- $files = File::files($directory);
-
- foreach ($files as $file) {
- require_once $file;
- }
- }
- }
-
- /**
- * Load all files from directory
- *
- * @param string $directory
- *
- * @return void
- */
- protected function loadAllFiles(string $directory): void
- {
- if (File::isDirectory($directory)) {
- $files = File::allFiles($directory);
-
- foreach ($files as $file) {
- require_once $file;
- }
- }
- }
-}
diff --git a/src/Traits/RouteProviderHelpersTrait.php b/src/Traits/RouteProviderHelpersTrait.php
deleted file mode 100644
index 5627bdb..0000000
--- a/src/Traits/RouteProviderHelpersTrait.php
+++ /dev/null
@@ -1,53 +0,0 @@
-loadRoutesFromDirectory(
- $nestedDirectory,
- $directoryRoutePrefix,
- $generateRoutePrefixesByNestedDirectories
- );
- }
-
- /** @var SplFileInfo[] $files */
- $files = Arr::sort(File::files($directory), function (SplFileInfo $file) {
- return $file->getFilename();
- });
-
- Route::prefix($routePrefix)->group(function () use ($files) {
- foreach ($files as $file) {
- require $file->getPathname();
- }
- });
- }
- }
-}
diff --git a/src/Traits/SanitizerTrait.php b/src/Traits/SanitizerTrait.php
deleted file mode 100644
index 4b0cfa6..0000000
--- a/src/Traits/SanitizerTrait.php
+++ /dev/null
@@ -1,88 +0,0 @@
-getData();
-
- $inputAsArray = [];
- $fieldsWithDefaultValue = [];
-
- // create a multidimensional array based on $fields
- // which was submitted as DOT notation (e.g., data.name)
- foreach ($fields as $key => $value) {
- if (is_string($key)) {
- // save fields with default values
- $fieldsWithDefaultValue[$key] = $value;
- Arr::set($inputAsArray, $key, $value);
- } else {
- Arr::set($inputAsArray, $value, true);
- }
- }
-
- // check, if the keys exist in both arrays
- $data = $this->recursiveArrayIntersectKey($data, $inputAsArray);
-
- // set default values if key doesn't exist
- foreach ($fieldsWithDefaultValue as $key => $value) {
- $data = Arr::add($data, $key, $value);
- }
-
- return $data;
- }
-
- /**
- * @throws LogicException
- */
- private function getData(): array
- {
- // get all request data
- if ($this instanceof Request) {
- $data = $this->all();
- } else {
- throw new LogicException('Unsupported class type for sanitization.');
- }
-
- return $data;
- }
-
- /**
- * Recursively intersects 2 arrays based on their keys.
- *
- * @param array $a first array (that keeps the values)
- * @param array $b second array to be compared with
- *
- * @return array an array containing all keys that are present in $a and $b. Only values from $a are returned
- */
- private function recursiveArrayIntersectKey(array $a, array $b): array
- {
- $a = array_intersect_key($a, $b);
-
- foreach ($a as $key => &$value) {
- if (is_array($value) && is_array($b[$key])) {
- $value = $this->recursiveArrayIntersectKey($value, $b[$key]);
- }
- }
-
- return $a;
- }
-}
diff --git a/src/Traits/TestsTraits/TestsAuthHelperTrait.php b/src/Traits/TestsTraits/TestsAuthHelperTrait.php
deleted file mode 100644
index cb2bf69..0000000
--- a/src/Traits/TestsTraits/TestsAuthHelperTrait.php
+++ /dev/null
@@ -1,184 +0,0 @@
-, roles:string|array}
- */
- protected array $access = [
- 'permissions' => '',
- 'roles' => '',
- ];
-
- /**
- * state name on User factory
- */
- private ?string $userAdminState = null;
-
- /**
- * create testing user as Admin.
- */
- private ?bool $createUserAsAdmin = null;
-
- /**
- * Same as `getTestingUser()` but always overrides the User Access
- * (roles and permissions) with null. So the user can be used to test
- * if unauthorized user tried to access your protected endpoint.
- *
- * @param null $userDetails
- * @return UserContract|null
- */
- public function getTestingUserWithoutAccess($userDetails = null): ?UserContract
- {
- return $this->getTestingUser($userDetails, $this->getNullAccess());
- }
-
- /**
- * Try to get the last logged-in User, if not found then create new one.
- * Note: if $userDetails are provided it will always create new user, even
- * if another one was previously created during the execution of your test.
- *
- * By default, Users will be given the Roles and Permissions found in the class
- * `$access` property. But the $access parameter can be used to override the
- * defined roles and permissions in the `$access` property of your class.
- *
- * @param array|null $userDetails what to be attached on the User object
- * @param array|null $access roles and permissions you'd like to provide this user with
- * @param bool $createUserAsAdmin should create testing user as admin
- * @return UserContract|null
- */
- public function getTestingUser(?array $userDetails = null, ?array $access = null, bool $createUserAsAdmin = false): ?UserContract
- {
- $this->createUserAsAdmin = $createUserAsAdmin;
- $this->userClass = $this->userClass ?? config('laraneat.tests.user-class');
-
- if (!$this->userClass) {
- throw new LogicException("User class was not provided");
- }
-
- $this->userAdminState = config('laraneat.tests.user-admin-state');
- return is_null($userDetails) ? $this->findOrCreateTestingUser($userDetails, $access)
- : $this->createTestingUser($userDetails, $access);
- }
-
- private function findOrCreateTestingUser($userDetails, $access): UserContract
- {
- return $this->testingUser ?: $this->createTestingUser($userDetails, $access);
- }
-
- private function createTestingUser(?array $userDetails = null, ?array $access = null): ?UserContract
- {
- // create new user
- $user = $this->factoryCreateUser($userDetails);
-
- // assign user roles and permissions based on the access property
- $user = $this->setupTestingUserAccess($user, $access);
-
- // authentication the user
- $this->actingAs($user, config('laraneat.tests.guard', 'api'));
-
- // set the created user
- return $this->testingUser = $user;
- }
-
- private function factoryCreateUser(?array $userDetails = null): UserContract
- {
- $user = str_replace('::class', '', $this->userClass);
- if ($this->createUserAsAdmin) {
- $state = $this->userAdminState;
- return $user::factory()->$state()->create($this->prepareUserDetails($userDetails));
- }
-
- return $user::factory()->create($this->prepareUserDetails($userDetails));
- }
-
- private function prepareUserDetails(?array $userDetails = null): array
- {
- $defaultUserDetails = [
- 'name' => $this->faker->name,
- 'email' => $this->faker->email,
- 'password' => 'testing-password',
- ];
-
- // if no user detail provided, use the default details, to find the password or generate one before encoding it
- return $this->prepareUserPassword($userDetails ?: $defaultUserDetails);
- }
-
- private function prepareUserPassword(?array $userDetails): ?array
- {
- // get password from the user details or generate one
- $password = $userDetails['password'] ?? $this->faker->password;
-
- // hash the password and set it back at the user details
- $userDetails['password'] = Hash::make($password);
-
- return $userDetails;
- }
-
- private function setupTestingUserAccess($user, ?array $access = null)
- {
- $access = $access ?: $this->getAccess();
-
- $user = $this->setupTestingUserPermissions($user, $access);
- return $this->setupTestingUserRoles($user, $access);
- }
-
- private function getAccess(): ?array
- {
- return $this->access ?? null;
- }
-
- private function setupTestingUserPermissions($user, ?array $access)
- {
- if (isset($access['permissions']) && !empty($access['permissions'])) {
- $user->givePermissionTo($access['permissions']);
- $user = $user->fresh();
- }
-
- return $user;
- }
-
- private function setupTestingUserRoles($user, ?array $access)
- {
- if (isset($access['roles']) && !empty($access['roles']) && !$user->hasRole($access['roles'])) {
- $user->assignRole($access['roles']);
- $user = $user->fresh();
- }
-
- return $user;
- }
-
- /**
- * @return null[]
- */
- private function getNullAccess(): array
- {
- return [
- 'permissions' => null,
- 'roles' => null
- ];
- }
-}
diff --git a/src/Traits/TestsTraits/TestsModelHelperTrait.php b/src/Traits/TestsTraits/TestsModelHelperTrait.php
deleted file mode 100644
index 46e78cc..0000000
--- a/src/Traits/TestsTraits/TestsModelHelperTrait.php
+++ /dev/null
@@ -1,46 +0,0 @@
-assertTrue(
- $this->makeQueryWhereColumns($subject, $columns)->exists(),
- sprintf('Model where columns (%s) not exists', http_build_query($columns))
- );
- }
-
- public function getModelsWhereColumns($subject, array $columns): Collection
- {
- return $this->makeQueryWhereColumns($subject, $columns)->get();
- }
-
- public function makeQueryWhereColumns($subject, array $columns): Builder|Relation
- {
- if (is_subclass_of($subject, Model::class)) {
- $subject = $subject::query();
- }
-
- throw_unless(
- $subject instanceof Builder || $subject instanceof Relation,
- InvalidSubject::make($subject)
- );
-
- foreach ($columns as $column => $value) {
- $subject->where($column, $value);
- }
-
- return $subject;
- }
-}
diff --git a/src/Traits/TestsTraits/TestsUrlHelperTrait.php b/src/Traits/TestsTraits/TestsUrlHelperTrait.php
deleted file mode 100644
index 412df5b..0000000
--- a/src/Traits/TestsTraits/TestsUrlHelperTrait.php
+++ /dev/null
@@ -1,68 +0,0 @@
- $value) {
- $url = Str::replace($key, $value, $url);
- }
-
- return $url;
- }
-
- public function trimSlashes($path): string
- {
- return trim($path, '/');
- }
-
- public function buildUrl(?string $path = null, array $queryParameters = [], array $replaces = []): string
- {
- $path = $path ?? $this->url ?? null;
-
- if (!$path) {
- throw InvalidPath::make($path);
- }
-
- if ($this->isAbsoluteUrl($path)) {
- return $this->addQueryParametersToUrl($path, $queryParameters);
- }
-
- $appUrl = $this->trimSlashes(config('app.url'));
- $url = $appUrl.'/'.$this->trimSlashes($path);
-
- if ($replaces) {
- $url = $this->replaceByKeyValues($url, $replaces);
- }
-
- return $this->addQueryParametersToUrl($url, $queryParameters);
- }
-
- public function isAbsoluteUrl(string $url): bool
- {
- return Str::startsWith($url, ['http://', 'https://']);
- }
-}
diff --git a/src/helpers.php b/src/helpers.php
deleted file mode 100755
index 0bf5a8a..0000000
--- a/src/helpers.php
+++ /dev/null
@@ -1,20 +0,0 @@
-getExtraPath($path);
- }
-}
diff --git a/tests/Activators/FileActivatorTest.php b/tests/Activators/FileActivatorTest.php
deleted file mode 100644
index aca311d..0000000
--- a/tests/Activators/FileActivatorTest.php
+++ /dev/null
@@ -1,86 +0,0 @@
-module = new TestModule($this->app, 'Article', __DIR__ . '/../fixtures/stubs/valid/Article', 'App\\Module\\Article');
- $this->finder = $this->app['files'];
- $this->activator = new FileActivator($this->app);
- }
-
- protected function tearDown(): void
- {
- $this->activator->reset();
- parent::tearDown();
- }
-
- /** @test */
- public function it_creates_valid_json_file_after_enabling()
- {
- $this->activator->enable($this->module);
- $this->assertMatchesSnapshot($this->finder->get($this->activator->getStatusesFilePath()));
-
- $this->activator->setActive($this->module, true);
- $this->assertMatchesSnapshot($this->finder->get($this->activator->getStatusesFilePath()));
- }
-
- /** @test */
- public function it_creates_valid_json_file_after_disabling()
- {
- $this->activator->disable($this->module);
- $this->assertMatchesSnapshot($this->finder->get($this->activator->getStatusesFilePath()));
-
- $this->activator->setActive($this->module, false);
- $this->assertMatchesSnapshot($this->finder->get($this->activator->getStatusesFilePath()));
- }
-
- /** @test */
- public function it_can_check_module_enabled_status()
- {
- $this->activator->enable($this->module);
- $this->assertTrue($this->activator->hasStatus($this->module, true));
-
- $this->activator->setActive($this->module, true);
- $this->assertTrue($this->activator->hasStatus($this->module, true));
- }
-
- /** @test */
- public function it_can_check_module_disabled_status()
- {
- $this->activator->disable($this->module);
- $this->assertTrue($this->activator->hasStatus($this->module, false));
-
- $this->activator->setActive($this->module, false);
- $this->assertTrue($this->activator->hasStatus($this->module, false));
- }
-
- /** @test */
- public function it_can_check_status_of_module_that_hasnt_been_enabled_or_disabled()
- {
- $this->assertTrue($this->activator->hasStatus($this->module, false));
- }
-}
-
-class TestModule extends \Laraneat\Modules\Module
-{
- public function registerProviders(): void
- {
- parent::registerProviders();
- }
-}
diff --git a/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_disabling__1.txt b/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_disabling__1.txt
deleted file mode 100644
index c740f0a..0000000
--- a/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_disabling__1.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Article": false
-}
\ No newline at end of file
diff --git a/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_disabling__2.txt b/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_disabling__2.txt
deleted file mode 100644
index c740f0a..0000000
--- a/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_disabling__2.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Article": false
-}
\ No newline at end of file
diff --git a/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_enabling__1.txt b/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_enabling__1.txt
deleted file mode 100644
index 7cbac35..0000000
--- a/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_enabling__1.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Article": true
-}
\ No newline at end of file
diff --git a/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_enabling__2.txt b/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_enabling__2.txt
deleted file mode 100644
index 7cbac35..0000000
--- a/tests/Activators/__snapshots__/FileActivatorTest__it_creates_valid_json_file_after_enabling__2.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Article": true
-}
\ No newline at end of file
diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php
deleted file mode 100644
index 2fc2161..0000000
--- a/tests/BaseTestCase.php
+++ /dev/null
@@ -1,193 +0,0 @@
-withoutMockingConsoleOutput();
- }
- }
-
- protected function getPackageProviders($app): array
- {
- return [
- ModulesServiceProvider::class,
- ];
- }
-
- /**
- * @param Application $app
- */
- protected function getEnvironmentSetUp($app): void
- {
- $app['config']->set('database.default', 'sqlite');
- $app['config']->set('database.connections.sqlite', [
- 'driver' => 'sqlite',
- 'database' => ':memory:',
- 'prefix' => '',
- ]);
-
- $app['config']->set('modules.paths.assets', public_path('modules'));
- $app['config']->set('modules.generator', [
- 'path' => base_path('app/Modules'),
- 'namespace' => 'App\\Modules',
- 'custom_stubs' => base_path('app/Ship/Generators/custom-stubs'),
- 'user_model' => 'App\\Modules\\User\\Models\\User',
- 'create_permission' => [
- 'action' => "App\\Modules\\Authorization\\Actions\\CreatePermissionAction",
- 'dto' => "App\\Modules\\Authorization\\DTO\\CreatePermissionDTO"
- ],
- 'components' => [
- 'action' => [
- 'path' => 'Actions',
- 'generate' => true
- ],
- 'api-controller' => [
- 'path' => 'UI/API/Controllers',
- 'generate' => false
- ],
- 'api-query-wizard' => [
- 'path' => 'UI/API/QueryWizards',
- 'generate' => true
- ],
- 'api-request' => [
- 'path' => 'UI/API/Requests',
- 'generate' => true
- ],
- 'api-resource' => [
- 'path' => 'UI/API/Resources',
- 'generate' => true
- ],
- 'api-route' => [
- 'path' => 'UI/API/Routes',
- 'generate' => true
- ],
- 'api-test' => [
- 'path' => 'UI/API/Tests',
- 'generate' => true
- ],
- 'cli-command' => [
- 'path' => 'UI/CLI/Commands',
- 'generate' => false
- ],
- 'cli-test' => [
- 'path' => 'UI/CLI/Tests',
- 'generate' => false
- ],
- 'dto' => [
- 'path' => 'DTO',
- 'generate' => true
- ],
- 'event' => [
- 'path' => 'Events',
- 'generate' => false
- ],
- 'exception' => [
- 'path' => 'Exceptions',
- 'generate' => false
- ],
- 'factory' => [
- 'path' => 'Data/Factories',
- 'generate' => true
- ],
- 'feature-test' => [
- 'path' => 'Tests/Feature',
- 'generate' => false
- ],
- 'job' => [
- 'path' => 'Jobs',
- 'generate' => false
- ],
- 'lang' => [
- 'path' => 'Resources/lang',
- 'generate' => false
- ],
- 'listener' => [
- 'path' => 'Listeners',
- 'generate' => false
- ],
- 'mail' => [
- 'path' => 'Mails',
- 'generate' => false
- ],
- 'middleware' => [
- 'path' => 'Middleware',
- 'generate' => false
- ],
- 'migration' => [
- 'path' => 'Data/Migrations',
- 'generate' => true
- ],
- 'model' => [
- 'path' => 'Models',
- 'generate' => true
- ],
- 'notification' => [
- 'path' => 'Notifications',
- 'generate' => false
- ],
- 'observer' => [
- 'path' => 'Observers',
- 'generate' => false
- ],
- 'policy' => [
- 'path' => 'Policies',
- 'generate' => true
- ],
- 'provider' => [
- 'path' => 'Providers',
- 'generate' => true
- ],
- 'rule' => [
- 'path' => 'Rules',
- 'generate' => false
- ],
- 'seeder' => [
- 'path' => 'Data/Seeders',
- 'generate' => true
- ],
- 'web-controller' => [
- 'path' => 'UI/WEB/Controllers',
- 'generate' => false
- ],
- 'web-request' => [
- 'path' => 'UI/WEB/Requests',
- 'generate' => false,
- ],
- 'web-route' => [
- 'path' => 'UI/WEB/Routes',
- 'generate' => false
- ],
- 'web-test' => [
- 'path' => 'UI/WEB/Tests',
- 'generate' => false
- ],
- 'view' => [
- 'path' => 'Resources/views',
- 'generate' => false
- ],
- 'unit-test' => [
- 'path' => 'Tests/Unit',
- 'generate' => false
- ],
- ],
- ]);
-
- $app['config']->set('modules.cache.enabled', true);
- $app['config']->set('modules.composer.composer-output', true);
- }
-}
diff --git a/tests/CollectionTest.php b/tests/CollectionTest.php
deleted file mode 100644
index 1412383..0000000
--- a/tests/CollectionTest.php
+++ /dev/null
@@ -1,68 +0,0 @@
- 'module-one',
- 'path' => __DIR__ . '/fixtures/stubs/valid/Article',
- 'namespace' => 'App\\SomeModules\\Article'
- ];
- $moduleTwoAttributes = [
- 'name' => 'module-two',
- 'path' =>__DIR__ . '/fixtures/stubs/valid/Requirement',
- 'namespace' => 'App\\SomeModules\\Requirement'
- ];
-
- $modules = [
- 'article' => new Module(
- $this->app,
- $moduleOneAttributes['name'],
- $moduleOneAttributes['path'],
- $moduleOneAttributes['namespace']
- ),
- 'requirement' => new Module(
- $this->app,
- $moduleTwoAttributes['name'],
- $moduleTwoAttributes['path'],
- $moduleTwoAttributes['namespace']
- ),
- ];
- $moduleOneJson = $modules['article']->json()->toArray();
- $moduleTwoJson = $modules['requirement']->json()->toArray();
- $collection = new Collection($modules);
- $collectionArray = $collection->toArray();
-
- $this->assertArrayHasKey('path', $collectionArray['article']);
- $this->assertEquals($moduleOneAttributes['path'], $collectionArray['article']['path']);
- $this->assertEquals($moduleOneAttributes['name'], $collectionArray['article']['name']);
- $this->assertEquals($moduleOneAttributes['namespace'], $collectionArray['article']['namespace']);
- $this->assertEquals($moduleOneJson, $collectionArray['article']['module_json']['module.json']);
-
- $this->assertArrayHasKey('path', $collectionArray['requirement']);
- $this->assertEquals($moduleTwoAttributes['path'], $collectionArray['requirement']['path']);
- $this->assertEquals($moduleTwoAttributes['name'], $collectionArray['requirement']['name']);
- $this->assertEquals($moduleTwoAttributes['namespace'], $collectionArray['requirement']['namespace']);
- $this->assertEquals($moduleTwoJson, $collectionArray['requirement']['module_json']['module.json']);
- }
-
- public function testMethodAllReturnsTheCollectionItems(): void
- {
- $modules = [
- 'article' => new Module($this->app, 'module-one', __DIR__ . '/fixtures/stubs/valid/Article', 'App\\Module\\Article'),
- 'requirement' => new Module($this->app, 'module-two', __DIR__ . '/fixtures/stubs/valid/Requirement', 'App\\Module\\Requirement'),
- ];
- $collection = new Collection($modules);
- $items = $collection->all();
-
- $this->assertCount(2, $items);
- $this->assertInstanceOf(Module::class, $items['article']);
- $this->assertInstanceOf(Module::class, $items['requirement']);
- }
-}
diff --git a/tests/Commands/BaseCommandTest.php b/tests/Commands/BaseCommandTest.php
new file mode 100644
index 0000000..63f62ea
--- /dev/null
+++ b/tests/Commands/BaseCommandTest.php
@@ -0,0 +1,513 @@
+setModules([
+ __DIR__ . '/../fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/../fixtures/stubs/modules/valid/article',
+ __DIR__ . '/../fixtures/stubs/modules/valid/author',
+ __DIR__ . '/../fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/../fixtures/stubs/modules/valid/empty',
+ __DIR__ . '/../fixtures/stubs/modules/valid/navigation',
+ ], $this->app->basePath('/modules'));
+});
+
+describe('single "module" argument', function () {
+ class CommandWithSingleModuleArgument extends BaseCommand
+ {
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'single-module-argument-command {module? : Module name}';
+
+ /**
+ * Execute the console command.
+ */
+ public function handle(): int
+ {
+ try {
+ $moduleToHandle = $this->getModuleArgumentOrFail();
+ $this->line($moduleToHandle->getPackageName());
+ } catch (ModuleNotFound $exception) {
+ $this->error($exception->getMessage());
+
+ return self::FAILURE;
+ }
+
+ return self::SUCCESS;
+ }
+ }
+
+ beforeEach(function () {
+ /** @var Illuminate\Foundation\Console\Kernel $console */
+ $console = $this->app[ConsoleKernelContract::class];
+ $console->registerCommand(new CommandWithSingleModuleArgument($this->app[ModulesRepository::class]));
+ });
+
+ it('can accept a package name as a single "module" argument', function () {
+ $this->artisan('single-module-argument-command laraneat/article-category')
+ ->expectsOutput('laraneat/article-category')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command laraneat/article')
+ ->expectsOutput('laraneat/article')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command laraneat/author')
+ ->expectsOutput('laraneat/author')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command laraneat/empty')
+ ->expectsOutput('laraneat/empty')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command empty/empty')
+ ->expectsOutput('empty/empty')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command laraneat/location')
+ ->expectsOutput('laraneat/location')
+ ->assertSuccessful();
+ });
+
+ it('can accept a module name as a single "module" argument', function () {
+ $this->artisan('single-module-argument-command Article')
+ ->expectsOutput('laraneat/article')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command article')
+ ->expectsOutput('laraneat/article')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command article-category')
+ ->expectsOutput('laraneat/article-category')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command ArticleCategory')
+ ->expectsOutput('laraneat/article-category')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command location')
+ ->expectsOutput('laraneat/location')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command Location')
+ ->expectsOutput('laraneat/location')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command navigation')
+ ->expectsOutput('laraneat/location')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command Navigation')
+ ->expectsOutput('laraneat/location')
+ ->assertSuccessful();
+ });
+
+ it('displays an error message when passing an invalid single "module" argument', function () {
+ $this->artisan('single-module-argument-command laraneat/articlee')
+ ->expectsOutput("Module with 'laraneat/articlee' name or package name does not exist!")
+ ->assertFailed();
+
+ $this->artisan('single-module-argument-command laraneat')
+ ->expectsOutput("Module with 'laraneat' name or package name does not exist!")
+ ->assertFailed();
+
+ $this->artisan('single-module-argument-command laraneat/article/')
+ ->expectsOutput("Module with 'laraneat/article/' name or package name does not exist!")
+ ->assertFailed();
+
+ $this->artisan('single-module-argument-command /article')
+ ->expectsOutput("Module with '/article' name or package name does not exist!")
+ ->assertFailed();
+
+ $this->artisan('single-module-argument-command articlee')
+ ->expectsOutput("Module with 'articlee' name or package name does not exist!")
+ ->assertFailed();
+ });
+
+ it('gives a module selection if the "module" argument is not passed', function () {
+ $this->artisan('single-module-argument-command')
+ ->expectsChoice(
+ question: 'Select one module',
+ answer: 'laraneat/empty',
+ answers: [
+ 'laraneat/article-category',
+ 'laraneat/article',
+ 'laraneat/author',
+ 'laraneat/empty',
+ 'empty/empty',
+ 'laraneat/location',
+ ]
+ )
+ ->expectsOutput('laraneat/empty')
+ ->assertSuccessful();
+ });
+
+ it('gives a module selection if 2 or more modules with the same names are found', function () {
+ $expectedChoiceOptions = [
+ 'laraneat/empty',
+ 'empty/empty',
+ ];
+
+ $this->artisan('single-module-argument-command Empty')
+ ->expectsChoice(
+ question: "2 modules with name 'Empty' found, please select one module from those found",
+ answer: 'empty/empty',
+ answers: $expectedChoiceOptions
+ )
+ ->expectsOutput('empty/empty')
+ ->assertSuccessful();
+
+ $this->artisan('single-module-argument-command empty')
+ ->expectsChoice(
+ question: "2 modules with name 'empty' found, please select one module from those found",
+ answer: 'laraneat/empty',
+ answers: $expectedChoiceOptions
+ )
+ ->expectsOutput('laraneat/empty')
+ ->assertSuccessful();
+ });
+});
+
+describe('multiple "module" argument', function () {
+ class CommandWithMultipleModuleArgument extends BaseCommand
+ {
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'multiple-module-argument-command {module?* : Module name(s) or package name(s)}';
+
+ /**
+ * Execute the console command.
+ */
+ public function handle(): int
+ {
+ try {
+ $modulesToHandle = $this->getModuleArgumentOrFail();
+ $this->line(
+ collect($modulesToHandle)
+ ->map(fn (\Laraneat\Modules\Module $module) => $module->getPackageName())
+ ->join(', ')
+ );
+ } catch (ModuleNotFound $exception) {
+ $this->error($exception->getMessage());
+
+ return self::FAILURE;
+ }
+
+ return self::SUCCESS;
+ }
+ }
+
+ beforeEach(function () {
+ /** @var Illuminate\Foundation\Console\Kernel $console */
+ $console = $this->app[ConsoleKernelContract::class];
+ $console->registerCommand(new CommandWithMultipleModuleArgument($this->app[ModulesRepository::class]));
+ });
+
+ it('can accept a package name as a multiple "module" argument', function () {
+ $this->artisan('multiple-module-argument-command laraneat/article laraneat/empty empty/empty')
+ ->expectsOutput('laraneat/article, laraneat/empty, empty/empty')
+ ->assertSuccessful();
+
+ $this->artisan('multiple-module-argument-command laraneat/article laraneat/article laraneat/empty empty/empty laraneat/empty')
+ ->expectsOutput('laraneat/article, laraneat/empty, empty/empty')
+ ->assertSuccessful();
+
+ $this->artisan('multiple-module-argument-command laraneat/author')
+ ->expectsOutput('laraneat/author')
+ ->assertSuccessful();
+
+ $this->artisan('multiple-module-argument-command laraneat/author laraneat/author laraneat/author')
+ ->expectsOutput('laraneat/author')
+ ->assertSuccessful();
+ });
+
+ it('can accept "all" as a multiple "module" argument', function () {
+ $this->artisan('multiple-module-argument-command all')
+ ->expectsOutput('laraneat/article-category, laraneat/article, laraneat/author, laraneat/empty, empty/empty, laraneat/location')
+ ->assertSuccessful();
+
+ $this->artisan('multiple-module-argument-command all laraneat/empty laraneat/author')
+ ->expectsOutput('laraneat/article-category, laraneat/article, laraneat/author, laraneat/empty, empty/empty, laraneat/location')
+ ->assertSuccessful();
+
+ $this->artisan('multiple-module-argument-command laraneat/empty all laraneat/author')
+ ->expectsOutput('laraneat/article-category, laraneat/article, laraneat/author, laraneat/empty, empty/empty, laraneat/location')
+ ->assertSuccessful();
+
+ $this->artisan('multiple-module-argument-command laraneat/author laraneat/empty all')
+ ->expectsOutput('laraneat/article-category, laraneat/article, laraneat/author, laraneat/empty, empty/empty, laraneat/location')
+ ->assertSuccessful();
+ });
+
+ it('can accept a module name as a multiple "module" argument', function () {
+ $this->artisan('multiple-module-argument-command Article location Navigation ArticleCategory Location article-category')
+ ->expectsOutput('laraneat/article, laraneat/location, laraneat/article-category')
+ ->assertSuccessful();
+
+ $this->artisan('multiple-module-argument-command ArticleCategory articleCategory article-category article_category')
+ ->expectsOutput('laraneat/article-category')
+ ->assertSuccessful();
+ });
+
+ it('can accept a module name and package name as a multiple "module" argument', function () {
+ $this->artisan('multiple-module-argument-command Article location Navigation empty/empty ArticleCategory Location article-category')
+ ->expectsOutput('laraneat/article, laraneat/location, empty/empty, laraneat/article-category')
+ ->assertSuccessful();
+
+ $this->artisan('multiple-module-argument-command ArticleCategory articleCategory laraneat/article-category article-category article_category')
+ ->expectsOutput('laraneat/article-category')
+ ->assertSuccessful();
+ });
+
+ it('displays an error message when passing an invalid multiple "module" argument', function () {
+ $this->artisan('multiple-module-argument-command laraneat/empty laraneat/articlee laraneat/navigation')
+ ->expectsOutput("Module with 'laraneat/articlee' name or package name does not exist!")
+ ->assertFailed();
+
+ $this->artisan('multiple-module-argument-command laraneat laraneat/navigation')
+ ->expectsOutput("Module with 'laraneat' name or package name does not exist!")
+ ->assertFailed();
+
+ $this->artisan('multiple-module-argument-command Author laraneat/navigation')
+ ->expectsOutput("Module with 'laraneat/navigation' name or package name does not exist!")
+ ->assertFailed();
+
+ $this->artisan('multiple-module-argument-command article /article')
+ ->expectsOutput("Module with '/article' name or package name does not exist!")
+ ->assertFailed();
+ });
+
+ it('gives a module selection if the multiple "module" argument is not passed', function () {
+ // Laravel's expectsChoice expects keys and values merged when using associative arrays
+ // The options are: ['all' => 'All modules', 'laraneat/article' => 'laraneat/article', ...]
+ // This results in: ['All modules', 'all', 'empty/empty', 'empty/empty', ...]
+ // In Laravel 10, Symfony adds empty string at position 0 and 'None' at position 2 for multiselect prompts
+ $isLaravel10 = version_compare(app()->version(), '11.0', '<');
+
+ $expectedAnswers = $isLaravel10
+ ? [
+ '', // empty string added by Symfony in Laravel 10
+ 'All modules',
+ 'None', // 'None' option added by Symfony in Laravel 10
+ 'all',
+ 'empty/empty',
+ 'empty/empty',
+ 'laraneat/article',
+ 'laraneat/article',
+ 'laraneat/article-category',
+ 'laraneat/article-category',
+ 'laraneat/author',
+ 'laraneat/author',
+ 'laraneat/empty',
+ 'laraneat/empty',
+ 'laraneat/location',
+ 'laraneat/location',
+ ]
+ : [
+ 'All modules',
+ 'all',
+ 'empty/empty',
+ 'empty/empty',
+ 'laraneat/article',
+ 'laraneat/article',
+ 'laraneat/article-category',
+ 'laraneat/article-category',
+ 'laraneat/author',
+ 'laraneat/author',
+ 'laraneat/empty',
+ 'laraneat/empty',
+ 'laraneat/location',
+ 'laraneat/location',
+ ];
+
+ $this->artisan('multiple-module-argument-command')
+ ->expectsChoice(
+ question: 'Select one or more module',
+ answer: ['laraneat/article', 'empty/empty', 'laraneat/location'],
+ answers: $expectedAnswers
+ )
+ ->expectsOutput('laraneat/article, empty/empty, laraneat/location')
+ ->assertSuccessful();
+ });
+
+ it('gives a module selection if 2 or more modules with the same names are found', function () {
+ $expectedChoiceOptions = [
+ 'laraneat/empty',
+ 'empty/empty',
+ ];
+
+ $this->artisan('multiple-module-argument-command empty laraneat/article Author Empty')
+ ->expectsChoice(
+ question: "2 modules with name 'empty' found, please select one module from those found",
+ answer: 'laraneat/empty',
+ answers: $expectedChoiceOptions
+ )
+ ->expectsChoice(
+ question: "2 modules with name 'Empty' found, please select one module from those found",
+ answer: 'laraneat/empty',
+ answers: $expectedChoiceOptions
+ )
+ ->expectsOutput('laraneat/empty, laraneat/article, laraneat/author')
+ ->assertSuccessful();
+
+ $this->artisan('multiple-module-argument-command empty laraneat/article Author Empty')
+ ->expectsChoice(
+ question: "2 modules with name 'empty' found, please select one module from those found",
+ answer: 'laraneat/empty',
+ answers: $expectedChoiceOptions
+ )
+ ->expectsChoice(
+ question: "2 modules with name 'Empty' found, please select one module from those found",
+ answer: 'empty/empty',
+ answers: $expectedChoiceOptions
+ )
+ ->expectsOutput('laraneat/empty, laraneat/article, laraneat/author, empty/empty')
+ ->assertSuccessful();
+ });
+});
+
+describe('getOptionOrAsk', function () {
+ class CommandWithOptionAsking extends BaseCommand
+ {
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'command-with-option-asking {--foo=}';
+
+ /**
+ * Execute the console command.
+ */
+ public function handle(): int
+ {
+ try {
+ $this->line($this->getOptionOrAsk('foo', 'Enter "foo" option'));
+ } catch (InvalidOptionException $exception) {
+ $this->line($exception->getMessage());
+
+ return self::FAILURE;
+ }
+
+ return self::SUCCESS;
+ }
+ }
+
+ beforeEach(function () {
+ /** @var Illuminate\Foundation\Console\Kernel $console */
+ $console = $this->app[ConsoleKernelContract::class];
+ $console->registerCommand(new CommandWithOptionAsking($this->app[ModulesRepository::class]));
+ });
+
+ it('asks for the option value if it is not specified', function () {
+ $this->artisan('command-with-option-asking')
+ ->expectsQuestion(
+ question: 'Enter "foo" option',
+ answer: 'some foo value',
+ )
+ ->expectsOutput('some foo value')
+ ->assertSuccessful();
+
+ $this->artisan('command-with-option-asking --foo=')
+ ->expectsQuestion(
+ question: 'Enter "foo" option',
+ answer: 'some foo value 2',
+ )
+ ->expectsOutput('some foo value 2')
+ ->assertSuccessful();
+
+ $this->artisan('command-with-option-asking')
+ ->expectsQuestion(
+ question: 'Enter "foo" option',
+ answer: '',
+ )
+ ->expectsOutput("The 'foo' option is required")
+ ->assertFailed();
+ });
+
+ it('does not ask for an option value if it specified', function () {
+ $this->artisan('command-with-option-asking --foo=some-foo-value')
+ ->expectsOutput('some-foo-value')
+ ->assertSuccessful();
+ });
+});
+
+describe('getOptionOrChoice', function () {
+ class CommandWithOptionChoice extends BaseCommand
+ {
+ public const CHOICES = ['first', 'second', 'third'];
+
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'command-with-option-choice {--foo=}';
+
+ /**
+ * Execute the console command.
+ */
+ public function handle(): int
+ {
+ try {
+ $this->line($this->getOptionOrChoice('foo', 'Choice the "foo" option', self::CHOICES));
+ } catch (InvalidOptionException $exception) {
+ $this->line($exception->getMessage());
+
+ return self::FAILURE;
+ }
+
+ return self::SUCCESS;
+ }
+ }
+
+ beforeEach(function () {
+ /** @var Illuminate\Foundation\Console\Kernel $console */
+ $console = $this->app[ConsoleKernelContract::class];
+ $console->registerCommand(new CommandWithOptionChoice($this->app[ModulesRepository::class]));
+ });
+
+ it('let you choose an option value if it is not specified', function () {
+ $this->artisan('command-with-option-choice')
+ ->expectsChoice(
+ question: 'Choice the "foo" option',
+ answer: 'first',
+ answers: CommandWithOptionChoice::CHOICES
+ )
+ ->expectsOutput('first')
+ ->assertSuccessful();
+
+ $this->artisan('command-with-option-choice --foo=')
+ ->expectsChoice(
+ question: 'Choice the "foo" option',
+ answer: 'second',
+ answers: CommandWithOptionChoice::CHOICES
+ )
+ ->expectsOutput('second')
+ ->assertSuccessful();
+ });
+
+ it('doesnt let you choose an option value if it specified', function () {
+ $this->artisan('command-with-option-choice --foo=first')
+ ->expectsOutput('first')
+ ->assertSuccessful();
+ });
+
+ it('shows an error if the passed option value is not valid', function () {
+ $this->artisan('command-with-option-choice --foo=some-invalid-value')
+ ->expectsOutput("Wrong 'foo' option value provided. Value should be one of 'first' or 'second' or 'third'.")
+ ->assertFailed();
+ });
+});
diff --git a/tests/Commands/CacheClearCommandTest.php b/tests/Commands/CacheClearCommandTest.php
new file mode 100644
index 0000000..779de5b
--- /dev/null
+++ b/tests/Commands/CacheClearCommandTest.php
@@ -0,0 +1,13 @@
+mock(ModulesRepository::class, function (MockInterface $mock) {
+ $mock->shouldReceive('pruneModulesManifest')->once();
+ });
+ $this->artisan('module:clear')
+ ->expectsOutputToContain('Modules manifest cache cleared!')
+ ->assertSuccessful();
+});
diff --git a/tests/Commands/CacheCommandTest.php b/tests/Commands/CacheCommandTest.php
new file mode 100644
index 0000000..6206208
--- /dev/null
+++ b/tests/Commands/CacheCommandTest.php
@@ -0,0 +1,13 @@
+mock(ModulesRepository::class, function (MockInterface $mock) {
+ $mock->shouldReceive('buildModulesManifest')->once();
+ });
+ $this->artisan('module:cache')
+ ->expectsOutputToContain('Modules manifest cached!')
+ ->assertSuccessful();
+});
diff --git a/tests/Commands/EnableCommandTest.php b/tests/Commands/EnableCommandTest.php
deleted file mode 100644
index a7cf59d..0000000
--- a/tests/Commands/EnableCommandTest.php
+++ /dev/null
@@ -1,57 +0,0 @@
-artisan('module:make', ['name' => 'Article']);
- $this->artisan('module:make', ['name' => 'Taxonomy']);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- $this->app[RepositoryInterface::class]->delete('Taxonomy');
- parent::tearDown();
- }
-
- /** @test */
- public function it_enables_a_module()
- {
- /** @var Module $blogModule */
- $blogModule = $this->app[RepositoryInterface::class]->find('Article');
- $blogModule->disable();
-
- $code = $this->artisan('module:enable', ['module' => 'Article']);
-
- $this->assertTrue($blogModule->isEnabled());
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_enables_all_modules()
- {
- /** @var Module $blogModule */
- $blogModule = $this->app[RepositoryInterface::class]->find('Article');
- $blogModule->disable();
-
- /** @var Module $taxonomyModule */
- $taxonomyModule = $this->app[RepositoryInterface::class]->find('Taxonomy');
- $taxonomyModule->disable();
-
- $code = $this->artisan('module:enable');
-
- $this->assertTrue($blogModule->isEnabled() && $taxonomyModule->isEnabled());
- $this->assertSame(0, $code);
- }
-}
diff --git a/tests/Commands/Generators/ActionMakeCommandTest.php b/tests/Commands/Generators/ActionMakeCommandTest.php
index 71cd4b5..33cfc04 100644
--- a/tests/Commands/Generators/ActionMakeCommandTest.php
+++ b/tests/Commands/Generators/ActionMakeCommandTest.php
@@ -1,203 +1,106 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_action_file()
- {
- $code = $this->artisan('module:make:action', [
- 'name' => 'MyAwesomeAction',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Actions/MyAwesomeAction.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_action_file_with_content()
- {
- $code = $this->artisan('module:make:action', [
- 'name' => 'MyAwesomeAction',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Actions/MyAwesomeAction.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path()
- {
- $this->app['config']->set('modules.generator.components.action.path', 'Foo/Bar\\NewActions');
-
- $code = $this->artisan('module:make:action', [
- 'name' => 'Baz\\Bat/MyAwesomeAction',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/NewActions/Baz/Bat/MyAwesomeAction.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace()
- {
- $this->app['config']->set('modules.generator.components.action.namespace', 'Foo/Bar\\NewActions/');
-
- $code = $this->artisan('module:make:action', [
- 'name' => 'Baz\\Bat/MyAwesomeAction',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Actions/Baz/Bat/MyAwesomeAction.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_create_action_file()
- {
- $code = $this->artisan('module:make:action', [
- 'name' => 'Baz\\Bat/MyAwesomeCreateAction',
- 'module' => 'Article',
- '--stub' => 'create',
- '--dto' => 'Foo/Bar\\TestDTO',
- '--model' => 'Bar/TestModel',
- '--request' => 'Bat/TestRequest',
- '--resource' => 'Baz\\TestResource',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Actions/Baz/Bat/MyAwesomeCreateAction.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_throws_exception_when_classes_not_provided_for_create_action_file()
- {
- $this->expectException(InvalidOptionException::class);
-
- $this->artisan('module:make:action', [
- 'name' => 'Baz\\Bat/MyAwesomeCreateAction',
- 'module' => 'Article',
- '--stub' => 'create',
- '-n' => '',
- ]);
- }
-
- /** @test */
- public function it_can_generate_delete_action_file()
- {
- $code = $this->artisan('module:make:action', [
- 'name' => 'Baz\\Bat/MyAwesomeDeleteAction',
- 'module' => 'Article',
- '--stub' => 'delete',
- '--model' => 'Bar/TestModel',
- '--request' => 'Bat/TestRequest',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Actions/Baz/Bat/MyAwesomeDeleteAction.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_list_action_file()
- {
- $code = $this->artisan('module:make:action', [
- 'name' => 'Baz\\Bat/MyAwesomeListAction',
- 'module' => 'Article',
- '--stub' => 'list',
- '--model' => 'Bar/TestModel',
- '--request' => 'Bat/TestRequest',
- '--resource' => 'Baz\\TestResource',
- '--wizard' => 'Bat\\TestQueryWizard',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Actions/Baz/Bat/MyAwesomeListAction.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_update_action_file()
- {
- $code = $this->artisan('module:make:action', [
- 'name' => 'Baz\\Bat/MyAwesomeUpdateAction',
- 'module' => 'Article',
- '--stub' => 'update',
- '--dto' => 'Foo/Bar\\TestDTO',
- '--model' => 'Bar/TestModel',
- '--request' => 'Bat/TestRequest',
- '--resource' => 'Baz\\TestResource',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Actions/Baz/Bat/MyAwesomeUpdateAction.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_view_action_file()
- {
- $code = $this->artisan('module:make:action', [
- 'name' => 'Baz\\Bat/MyAwesomeViewAction',
- 'module' => 'Article',
- '--stub' => 'view',
- '--model' => 'Bar/TestModel',
- '--request' => 'Bat/TestRequest',
- '--resource' => 'Baz\\TestResource',
- '--wizard' => 'Bat\\TestQueryWizard',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Actions/Baz/Bat/MyAwesomeViewAction.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "plain" action for the module', function () {
+ $this->artisan('module:make:action', [
+ 'name' => 'PlainAuthorAction',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Actions/PlainAuthorAction.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "create" action for the module', function () {
+ $this->artisan('module:make:action', [
+ 'name' => 'CreateAuthorAction',
+ 'module' => 'Author',
+ '--stub' => 'create',
+ '--dto' => 'CreateAuthorDTO',
+ '--model' => 'Author',
+ '--request' => 'CreateAuthorRequest',
+ '--resource' => 'AuthorResource',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Actions/CreateAuthorAction.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "update" action for the module', function () {
+ $this->artisan('module:make:action', [
+ 'name' => 'UpdateAuthorAction',
+ 'module' => 'Author',
+ '--stub' => 'update',
+ '--dto' => 'UpdateAuthorDTO',
+ '--model' => 'Author',
+ '--request' => 'UpdateAuthorRequest',
+ '--resource' => 'AuthorResource',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Actions/UpdateAuthorAction.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "delete" action for the module', function () {
+ $this->artisan('module:make:action', [
+ 'name' => 'DeleteAuthorAction',
+ 'module' => 'Author',
+ '--stub' => 'delete',
+ '--model' => 'Author',
+ '--request' => 'DeleteAuthorRequest',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Actions/DeleteAuthorAction.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "view" action for the module', function () {
+ $this->artisan('module:make:action', [
+ 'name' => 'ViewAuthorAction',
+ 'module' => 'Author',
+ '--stub' => 'view',
+ '--model' => 'Author',
+ '--request' => 'ViewAuthorRequest',
+ '--resource' => 'AuthorResource',
+ '--wizard' => 'AuthorQueryWizard',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Actions/ViewAuthorAction.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "list" action for the module', function () {
+ $this->artisan('module:make:action', [
+ 'name' => 'ListAuthorsAction',
+ 'module' => 'Author',
+ '--stub' => 'list',
+ '--model' => 'Author',
+ '--request' => 'ListAuthorsRequest',
+ '--resource' => 'AuthorResource',
+ '--wizard' => 'AuthorsQueryWizard',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Actions/ListAuthorsAction.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/BaseComponentGeneratorCommandTest.php b/tests/Commands/Generators/BaseComponentGeneratorCommandTest.php
new file mode 100644
index 0000000..a29f586
--- /dev/null
+++ b/tests/Commands/Generators/BaseComponentGeneratorCommandTest.php
@@ -0,0 +1,160 @@
+setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/article',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/empty',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/navigation',
+ ], $this->app->basePath('/modules'));
+});
+
+describe('getFullClassFromOptionOrAsk()', function () {
+ class GetFullClassFromOptionOrAskTestCommand extends BaseComponentGeneratorCommand
+ {
+ protected $signature = 'test:command {module?} {--model=}';
+
+ public function handle(): int
+ {
+ $module = $this->getModuleArgumentOrFail();
+ $modelClass = $this->getFullClassFromOptionOrAsk(
+ optionName: 'model',
+ question: 'Enter "model" class name',
+ componentType: ModuleComponentType::Model,
+ module: $module
+ );
+ $this->line($modelClass);
+
+ return self::SUCCESS;
+ }
+
+ protected function getContents(): string
+ {
+ return '';
+ }
+ }
+
+ beforeEach(function () {
+ /** @var Illuminate\Foundation\Console\Kernel $console */
+ $console = $this->app[ConsoleKernelContract::class];
+ $console->registerCommand(new GetFullClassFromOptionOrAskTestCommand(
+ $this->app[ModulesRepository::class],
+ $this->app[Filesystem::class],
+ ));
+ });
+
+
+ it('returns the full class of component if only the base class name is specified', function () {
+ $this->artisan('test:command', [
+ 'module' => 'navigation',
+ '--model' => 'SomeGeoLocationModel',
+ ])
+ ->expectsOutput('Modules\\GeoLocation\\Models\\SomeGeoLocationModel');
+
+ $this->artisan('test:command', [
+ 'module' => 'navigation',
+ '--model' => 'Some\\GeoLocationModel',
+ ])
+ ->expectsOutput('Modules\\GeoLocation\\Models\\Some\\GeoLocationModel');
+
+ $this->artisan('test:command', [
+ 'module' => 'navigation',
+ ])
+ ->expectsQuestion('Enter "model" class name', 'SomeGeoLocationModel')
+ ->expectsOutput('Modules\\GeoLocation\\Models\\SomeGeoLocationModel');
+
+ $this->artisan('test:command', [
+ 'module' => 'navigation',
+ ])
+ ->expectsQuestion('Enter "model" class name', 'Some\\GeoLocationModel')
+ ->expectsOutput('Modules\\GeoLocation\\Models\\Some\\GeoLocationModel');
+ });
+
+ it('returns the specified class if it begins with a backslash', function () {
+ $this->artisan('test:command', [
+ 'module' => 'navigation',
+ ])
+ ->expectsQuestion('Enter "model" class name', '\\Modules\\Article\\Models\\Article')
+ ->expectsOutput('\\Modules\\Article\\Models\\Article');
+
+ $this->artisan('test:command', [
+ 'module' => 'navigation',
+ '--model' => '\\Modules\\Article\\Models\\Article',
+ ])
+ ->expectsOutput('\\Modules\\Article\\Models\\Article');
+
+ $this->artisan('test:command', [
+ 'module' => 'navigation',
+ ])
+ ->expectsQuestion('Enter "model" class name', '\\Modules\\GeoLocation\\Models\\GeoLocation')
+ ->expectsOutput('\\Modules\\GeoLocation\\Models\\GeoLocation');
+
+ $this->artisan('test:command', [
+ 'module' => 'navigation',
+ '--model' => '\\Modules\\GeoLocation\\Models\\GeoLocation',
+ ])
+ ->expectsOutput('\\Modules\\GeoLocation\\Models\\GeoLocation');
+ });
+});
+
+describe('class name validation', function () {
+ it('rejects invalid class names starting with a number', function () {
+ $this->artisan('module:make:action', [
+ 'name' => '123Invalid',
+ 'module' => 'Author',
+ ])
+ ->expectsOutputToContain('not a valid PHP class name')
+ ->assertFailed();
+ });
+
+ it('rejects invalid class names with special characters', function () {
+ $this->artisan('module:make:action', [
+ 'name' => 'Invalid-Class',
+ 'module' => 'Author',
+ ])
+ ->expectsOutputToContain('not a valid PHP class name')
+ ->assertFailed();
+ });
+
+ it('rejects invalid class names with spaces', function () {
+ $this->artisan('module:make:action', [
+ 'name' => 'Invalid Class',
+ 'module' => 'Author',
+ ])
+ ->expectsOutputToContain('not a valid PHP class name')
+ ->assertFailed();
+ });
+
+ it('accepts valid class names', function () {
+ $this->artisan('module:make:action', [
+ 'name' => 'ValidAction',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ ])
+ ->assertSuccessful();
+
+ $this->artisan('module:make:action', [
+ 'name' => '_ValidAction',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ '--force' => true,
+ ])
+ ->assertSuccessful();
+
+ $this->artisan('module:make:action', [
+ 'name' => 'Valid123Action',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ '--force' => true,
+ ])
+ ->assertSuccessful();
+ });
+});
diff --git a/tests/Commands/Generators/CommandMakeCommandTest.php b/tests/Commands/Generators/CommandMakeCommandTest.php
index 9aff431..fc827b6 100644
--- a/tests/Commands/Generators/CommandMakeCommandTest.php
+++ b/tests/Commands/Generators/CommandMakeCommandTest.php
@@ -1,96 +1,24 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_command_file()
- {
- $code = $this->artisan('module:make:command', [
- 'name' => 'MyAwesomeCommand',
- 'module' => 'Article',
- '-n' => true,
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/CLI/Commands/MyAwesomeCommand.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_command_file_with_content()
- {
- $code = $this->artisan('module:make:command', [
- 'name' => 'Foo/Bar\\MyAwesomeCommand',
- 'module' => 'Article',
- '--command' => 'my:awesome:command'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/CLI/Commands/Foo/Bar/MyAwesomeCommand.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_command_file()
- {
- $this->app['config']->set('modules.generator.components.cli-command.path', 'Foo/Bar\\Commands');
-
- $code = $this->artisan('module:make:command', [
- 'name' => 'Baz\\Bat/MyAwesomeCommand',
- 'module' => 'Article',
- '--command' => 'my:awesome:command'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Commands/Baz/Bat/MyAwesomeCommand.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_command_file()
- {
- $this->app['config']->set('modules.generator.components.cli-command.namespace', 'Foo/Bar\\Commands/');
-
- $code = $this->artisan('module:make:command', [
- 'name' => 'Baz\\Bat/MyAwesomeCommand',
- 'module' => 'Article',
- '--command' => 'my:awesome:command'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/CLI/Commands/Baz/Bat/MyAwesomeCommand.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates console command for the module', function () {
+ $this->artisan('module:make:command', [
+ 'name' => 'SomeAuthorCommand',
+ 'module' => 'Author',
+ '--signature' => 'author:some-command {--foo : foo option}',
+ '--description' => 'Some author command description',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/CLI/Commands/SomeAuthorCommand.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/ComponentsMakeCommandTest.php b/tests/Commands/Generators/ComponentsMakeCommandTest.php
deleted file mode 100644
index bd233c7..0000000
--- a/tests/Commands/Generators/ComponentsMakeCommandTest.php
+++ /dev/null
@@ -1,191 +0,0 @@
-artisan('module:make', ['name' => 'Article', '--plain' => true]);
- $this->modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->repository = $this->app[RepositoryInterface::class];
- $this->activator = $this->app[ActivatorInterface::class];
- $this->moduleComponentPaths = [
- 'Actions/CreateArticleAction.php',
- 'Actions/UpdateArticleAction.php',
- 'Actions/DeleteArticleAction.php',
- 'Actions/ViewArticleAction.php',
- 'Actions/ListArticlesAction.php',
- 'Data/Factories/ArticleFactory.php',
- 'Data/Seeders/ArticlePermissionsSeeder_1.php',
- 'DTO/CreateArticleDTO.php',
- 'Models/Article.php',
- 'Policies/ArticlePolicy.php',
- 'Providers/ArticleServiceProvider.php',
- 'Providers/RouteServiceProvider.php',
- 'UI/API/QueryWizards/ArticleQueryWizard.php',
- 'UI/API/QueryWizards/ArticlesQueryWizard.php',
- 'UI/API/Resources/ArticleResource.php',
- 'UI/API/Requests/CreateArticleRequest.php',
- 'UI/API/Requests/UpdateArticleRequest.php',
- 'UI/API/Requests/DeleteArticleRequest.php',
- 'UI/API/Requests/ViewArticleRequest.php',
- 'UI/API/Requests/ListArticlesRequest.php',
- 'UI/API/Routes/v1/create_article.php',
- 'UI/API/Routes/v1/update_article.php',
- 'UI/API/Routes/v1/delete_article.php',
- 'UI/API/Routes/v1/view_article.php',
- 'UI/API/Routes/v1/list_articles.php',
- 'UI/API/Tests/CreateArticleTest.php',
- 'UI/API/Tests/UpdateArticleTest.php',
- 'UI/API/Tests/DeleteArticleTest.php',
- 'UI/API/Tests/ViewArticleTest.php',
- 'UI/API/Tests/ListArticlesTest.php',
- ];
- }
-
- protected function tearDown(): void
- {
- $this->finder->deleteDirectory($this->modulePath);
- if ($this->finder->isDirectory(base_path('app/Modules/Blog'))) {
- $this->finder->deleteDirectory(base_path('app/Modules/Blog'));
- }
- $this->activator->reset();
-
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_module_components()
- {
- $code = $this->artisan('module:make:components', [
- 'name' => 'Article',
- ]);
-
- foreach ($this->moduleComponentPaths as $componentPath) {
- $path = $this->modulePath . '/' . $componentPath;
- $this->assertFileExists($path);
- $this->assertMatchesSnapshot($this->finder->get($path));
- }
-
- $migrationFiles = $this->finder->allFiles($this->modulePath . '/Data/Migrations');
- $this->assertCount(1, $migrationFiles);
- $this->assertMatchesSnapshot($migrationFiles[0]->getContents());
-
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_set_custom_model()
- {
- $this->artisan('module:make', ['name' => 'Blog', '--entity' => 'Post']);
- $this->artisan('module:make:components', ['name' => 'Blog', '--entity' => 'Comment']);
-
- $modulePath = base_path('app/Modules/Blog');
- $moduleComponentPaths = [
- 'Actions/CreatePostAction.php',
- 'Actions/UpdatePostAction.php',
- 'Actions/DeletePostAction.php',
- 'Actions/ViewPostAction.php',
- 'Actions/ListPostsAction.php',
- 'Data/Factories/PostFactory.php',
- 'Data/Seeders/PostPermissionsSeeder_1.php',
- 'DTO/CreatePostDTO.php',
- 'Models/Post.php',
- 'Policies/PostPolicy.php',
- 'Providers/BlogServiceProvider.php',
- 'Providers/RouteServiceProvider.php',
- 'UI/API/QueryWizards/PostQueryWizard.php',
- 'UI/API/QueryWizards/PostsQueryWizard.php',
- 'UI/API/Resources/PostResource.php',
- 'UI/API/Requests/CreatePostRequest.php',
- 'UI/API/Requests/UpdatePostRequest.php',
- 'UI/API/Requests/DeletePostRequest.php',
- 'UI/API/Requests/ViewPostRequest.php',
- 'UI/API/Requests/ListPostsRequest.php',
- 'UI/API/Routes/v1/create_post.php',
- 'UI/API/Routes/v1/update_post.php',
- 'UI/API/Routes/v1/delete_post.php',
- 'UI/API/Routes/v1/view_post.php',
- 'UI/API/Routes/v1/list_posts.php',
- 'UI/API/Tests/CreatePostTest.php',
- 'UI/API/Tests/UpdatePostTest.php',
- 'UI/API/Tests/DeletePostTest.php',
- 'UI/API/Tests/ViewPostTest.php',
- 'UI/API/Tests/ListPostsTest.php',
-
- 'Actions/CreateCommentAction.php',
- 'Actions/UpdateCommentAction.php',
- 'Actions/DeleteCommentAction.php',
- 'Actions/ViewCommentAction.php',
- 'Actions/ListCommentsAction.php',
- 'Data/Factories/CommentFactory.php',
- 'Data/Seeders/CommentPermissionsSeeder_1.php',
- 'DTO/CreateCommentDTO.php',
- 'Models/Comment.php',
- 'Policies/CommentPolicy.php',
- 'Providers/BlogServiceProvider.php',
- 'Providers/RouteServiceProvider.php',
- 'UI/API/QueryWizards/CommentQueryWizard.php',
- 'UI/API/QueryWizards/CommentsQueryWizard.php',
- 'UI/API/Resources/CommentResource.php',
- 'UI/API/Requests/CreateCommentRequest.php',
- 'UI/API/Requests/UpdateCommentRequest.php',
- 'UI/API/Requests/DeleteCommentRequest.php',
- 'UI/API/Requests/ViewCommentRequest.php',
- 'UI/API/Requests/ListCommentsRequest.php',
- 'UI/API/Routes/v1/create_comment.php',
- 'UI/API/Routes/v1/update_comment.php',
- 'UI/API/Routes/v1/delete_comment.php',
- 'UI/API/Routes/v1/view_comment.php',
- 'UI/API/Routes/v1/list_comments.php',
- 'UI/API/Tests/CreateCommentTest.php',
- 'UI/API/Tests/UpdateCommentTest.php',
- 'UI/API/Tests/DeleteCommentTest.php',
- 'UI/API/Tests/ViewCommentTest.php',
- 'UI/API/Tests/ListCommentsTest.php',
- ];
-
- $moduleJsonPath = $modulePath . '/module.json';
- $this->assertFileExists($moduleJsonPath);
- $this->assertMatchesSnapshot($this->finder->get($moduleJsonPath));
-
- $composerJsonPath = $modulePath . '/composer.json';
- $this->assertFileExists($composerJsonPath);
- $this->assertMatchesSnapshot($this->finder->get($composerJsonPath));
-
- foreach ($moduleComponentPaths as $componentPath) {
- $path = $modulePath . '/' . $componentPath;
- $this->assertFileExists($path);
- $this->assertMatchesSnapshot($this->finder->get($path));
- }
-
- $migrationFiles = $this->finder->allFiles($modulePath . '/Data/Migrations');
- $this->assertCount(2, $migrationFiles);
- $this->assertMatchesSnapshot($migrationFiles[0]->getContents());
- $this->assertMatchesSnapshot($migrationFiles[1]->getContents());
- }
-}
diff --git a/tests/Commands/Generators/ControllerMakeCommandTest.php b/tests/Commands/Generators/ControllerMakeCommandTest.php
index bd5af61..b5b8296 100644
--- a/tests/Commands/Generators/ControllerMakeCommandTest.php
+++ b/tests/Commands/Generators/ControllerMakeCommandTest.php
@@ -1,158 +1,36 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_api_controller_file()
- {
- $code = $this->artisan('module:make:controller', [
- 'name' => 'MyAwesomeAPIController',
- 'module' => 'Article',
- '--ui' => 'api'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/API/Controllers/MyAwesomeAPIController.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_web_controller_file()
- {
- $code = $this->artisan('module:make:controller', [
- 'name' => 'MyAwesomeWEBController',
- 'module' => 'Article',
- '--ui' => 'web'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/WEB/Controllers/MyAwesomeWEBController.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_api_controller_file_with_content()
- {
- $code = $this->artisan('module:make:controller', [
- 'name' => 'Foo/Bar\\MyAwesomeAPIController',
- 'module' => 'Article',
- '--ui' => 'api'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Controllers/Foo/Bar/MyAwesomeAPIController.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_web_controller_file_with_content()
- {
- $code = $this->artisan('module:make:controller', [
- 'name' => 'Foo/Bar\\MyAwesomeWEBController',
- 'module' => 'Article',
- '--ui' => 'web'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Controllers/Foo/Bar/MyAwesomeWEBController.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_api_controller_file()
- {
- $this->app['config']->set('modules.generator.components.api-controller.path', 'Foo/Bar\\Controllers');
-
- $code = $this->artisan('module:make:controller', [
- 'name' => 'Baz\\Bat/MyAwesomeAPIController',
- 'module' => 'Article',
- '--ui' => 'api'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Controllers/Baz/Bat/MyAwesomeAPIController.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_api_controller_file()
- {
- $this->app['config']->set('modules.generator.components.api-controller.namespace', 'Foo/Bar\\Controllers/');
-
- $code = $this->artisan('module:make:controller', [
- 'name' => 'Baz\\Bat/MyAwesomeAPIController',
- 'module' => 'Article',
- '--ui' => 'api'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Controllers/Baz/Bat/MyAwesomeAPIController.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_web_controller_file()
- {
- $this->app['config']->set('modules.generator.components.web-controller.path', 'Foo/Bar\\Controllers');
-
- $code = $this->artisan('module:make:controller', [
- 'name' => 'Baz\\Bat/MyAwesomeWEBController',
- 'module' => 'Article',
- '--ui' => 'web'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Controllers/Baz/Bat/MyAwesomeWEBController.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_web_controller_file()
- {
- $this->app['config']->set('modules.generator.components.web-controller.namespace', 'Foo/Bar\\Controllers/');
-
- $code = $this->artisan('module:make:controller', [
- 'name' => 'Baz\\Bat/MyAwesomeWEBController',
- 'module' => 'Article',
- '--ui' => 'web'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Controllers/Baz/Bat/MyAwesomeWEBController.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "api" controller for the module', function () {
+ $this->artisan('module:make:controller', [
+ 'name' => 'ApiAuthorController',
+ 'module' => 'Author',
+ '--ui' => 'api',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/Controllers/ApiAuthorController.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "web" controller for the module', function () {
+ $this->artisan('module:make:controller', [
+ 'name' => 'WebAuthorController',
+ 'module' => 'Author',
+ '--ui' => 'web',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/Controllers/WebAuthorController.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/DTOMakeCommandTest.php b/tests/Commands/Generators/DTOMakeCommandTest.php
index 386cc12..fe221d6 100644
--- a/tests/Commands/Generators/DTOMakeCommandTest.php
+++ b/tests/Commands/Generators/DTOMakeCommandTest.php
@@ -1,92 +1,22 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_dto_file()
- {
- $code = $this->artisan('module:make:dto', [
- 'name' => 'MyAwesomeDTO',
- 'module' => 'Article',
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/DTO/MyAwesomeDTO.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_dto_file()
- {
- $code = $this->artisan('module:make:dto', [
- 'name' => 'Foo/Bar\\MyAwesomeDTO',
- 'module' => 'Article'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/DTO/Foo/Bar/MyAwesomeDTO.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_dto_file()
- {
- $this->app['config']->set('modules.generator.components.dto.path', 'Foo/Bar\\DTO');
-
- $code = $this->artisan('module:make:dto', [
- 'name' => 'Baz\\Bat/MyAwesomeDTO',
- 'module' => 'Article'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/DTO/Baz/Bat/MyAwesomeDTO.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_dto_file()
- {
- $this->app['config']->set('modules.generator.components.dto.namespace', 'Foo/Bar\\DTO/');
-
- $code = $this->artisan('module:make:dto', [
- 'name' => 'Baz\\Bat/MyAwesomeDTO',
- 'module' => 'Article'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/DTO/Baz/Bat/MyAwesomeDTO.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates dto for the module', function () {
+ $this->artisan('module:make:dto', [
+ 'name' => 'SomeAuthorDTO',
+ 'module' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/DTO/SomeAuthorDTO.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/EventMakeCommandTest.php b/tests/Commands/Generators/EventMakeCommandTest.php
index 7dcd602..d0482ff 100644
--- a/tests/Commands/Generators/EventMakeCommandTest.php
+++ b/tests/Commands/Generators/EventMakeCommandTest.php
@@ -1,92 +1,22 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_event_file()
- {
- $code = $this->artisan('module:make:event', [
- 'name' => 'MyAwesomeEvent',
- 'module' => 'Article'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Events/MyAwesomeEvent.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_event_file_with_content()
- {
- $code = $this->artisan('module:make:event', [
- 'name' => 'Foo/Bar\\MyAwesomeEvent',
- 'module' => 'Article'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Events/Foo/Bar/MyAwesomeEvent.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_event_file()
- {
- $this->app['config']->set('modules.generator.components.event.path', 'Foo/Bar\\Events');
-
- $code = $this->artisan('module:make:event', [
- 'name' => 'Baz\\Bat/MyAwesomeEvent',
- 'module' => 'Article'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Events/Baz/Bat/MyAwesomeEvent.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_event_file()
- {
- $this->app['config']->set('modules.generator.components.event.namespace', 'Foo/Bar\\Events/');
-
- $code = $this->artisan('module:make:event', [
- 'name' => 'Baz\\Bat/MyAwesomeEvent',
- 'module' => 'Article'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Events/Baz/Bat/MyAwesomeEvent.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates event for the module', function () {
+ $this->artisan('module:make:event', [
+ 'name' => 'SomeAuthorEvent',
+ 'module' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Events/SomeAuthorEvent.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/ExceptionMakeCommandTest.php b/tests/Commands/Generators/ExceptionMakeCommandTest.php
index 7c5be37..b5943a4 100644
--- a/tests/Commands/Generators/ExceptionMakeCommandTest.php
+++ b/tests/Commands/Generators/ExceptionMakeCommandTest.php
@@ -1,92 +1,22 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_exception_file()
- {
- $code = $this->artisan('module:make:exception', [
- 'name' => 'MyAwesomeException',
- 'module' => 'Article',
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Exceptions/MyAwesomeException.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_exception_file_with_content()
- {
- $code = $this->artisan('module:make:exception', [
- 'name' => 'Foo/Bar\\MyAwesomeException',
- 'module' => 'Article',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Exceptions/Foo/Bar/MyAwesomeException.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_exception_file()
- {
- $this->app['config']->set('modules.generator.components.exception.path', 'Foo/Bar\\Exceptions');
-
- $code = $this->artisan('module:make:exception', [
- 'name' => 'Baz\\Bat/MyAwesomeException',
- 'module' => 'Article',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Exceptions/Baz/Bat/MyAwesomeException.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_exception_file()
- {
- $this->app['config']->set('modules.generator.components.exception.namespace', 'Foo/Bar\\Exceptions/');
-
- $code = $this->artisan('module:make:exception', [
- 'name' => 'Baz\\Bat/MyAwesomeException',
- 'module' => 'Article',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Exceptions/Baz/Bat/MyAwesomeException.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates exception for the module', function () {
+ $this->artisan('module:make:exception', [
+ 'name' => 'SomeAuthorException',
+ 'module' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Exceptions/SomeAuthorException.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/FactoryMakeCommandTest.php b/tests/Commands/Generators/FactoryMakeCommandTest.php
index e26f47a..8dc4410 100644
--- a/tests/Commands/Generators/FactoryMakeCommandTest.php
+++ b/tests/Commands/Generators/FactoryMakeCommandTest.php
@@ -1,96 +1,23 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_factory_file()
- {
- $code = $this->artisan('module:make:factory', [
- 'name' => 'MyAwesomeFactory',
- 'module' => 'Article',
- '--model' => 'Some\\Nested/Model'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Data/Factories/MyAwesomeFactory.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_factory_file_with_content()
- {
- $code = $this->artisan('module:make:factory', [
- 'name' => 'Foo/Bar\\MyAwesomeFactory',
- 'module' => 'Article',
- '--model' => 'Some\\Nested/Model'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Data/Factories/Foo/Bar/MyAwesomeFactory.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_factory_file()
- {
- $this->app['config']->set('modules.generator.components.factory.path', 'Foo/Bar\\Factories');
-
- $code = $this->artisan('module:make:factory', [
- 'name' => 'Baz\\Bat/MyAwesomeFactory',
- 'module' => 'Article',
- '--model' => 'Some\\Nested/Model'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Factories/Baz/Bat/MyAwesomeFactory.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_factory_file()
- {
- $this->app['config']->set('modules.generator.components.factory.namespace', 'Foo/Bar\\Factories/');
-
- $code = $this->artisan('module:make:factory', [
- 'name' => 'Baz\\Bat/MyAwesomeFactory',
- 'module' => 'Article',
- '--model' => 'Some\\Nested/Model'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Data/Factories/Baz/Bat/MyAwesomeFactory.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates factory for the module', function () {
+ $this->artisan('module:make:factory', [
+ 'name' => 'SomeAuthorFactory',
+ 'module' => 'Author',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/database/factories/SomeAuthorFactory.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/JobMakeCommandTest.php b/tests/Commands/Generators/JobMakeCommandTest.php
index 94d2a57..d43b528 100644
--- a/tests/Commands/Generators/JobMakeCommandTest.php
+++ b/tests/Commands/Generators/JobMakeCommandTest.php
@@ -1,124 +1,36 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_plain_job_file()
- {
- $code = $this->artisan('module:make:job', [
- 'name' => 'MyAwesomePlainJob',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Jobs/MyAwesomePlainJob.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_queued_job_file()
- {
- $code = $this->artisan('module:make:job', [
- 'name' => 'MyAwesomeQueuedJob',
- 'module' => 'Article',
- '--stub' => 'queued'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Jobs/MyAwesomeQueuedJob.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_plain_job_file_with_content()
- {
- $code = $this->artisan('module:make:job', [
- 'name' => 'Foo/Bar\\MyAwesomePlainJob',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Jobs/Foo/Bar/MyAwesomePlainJob.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_queued_job_file_with_content()
- {
- $code = $this->artisan('module:make:job', [
- 'name' => 'Foo/Bar\\MyAwesomeQueuedJob',
- 'module' => 'Article',
- '--stub' => 'queued'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Jobs/Foo/Bar/MyAwesomeQueuedJob.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_plain_job_file()
- {
- $this->app['config']->set('modules.generator.components.job.path', 'Foo/Bar\\Jobs');
-
- $code = $this->artisan('module:make:job', [
- 'name' => 'Baz\\Bat/MyAwesomePlainJob',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Jobs/Baz/Bat/MyAwesomePlainJob.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_plain_job_file()
- {
- $this->app['config']->set('modules.generator.components.job.namespace', 'Foo/Bar\\Jobs/');
-
- $code = $this->artisan('module:make:job', [
- 'name' => 'Baz\\Bat/MyAwesomePlainJob',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Jobs/Baz/Bat/MyAwesomePlainJob.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "plain" job for the module', function () {
+ $this->artisan('module:make:job', [
+ 'name' => 'PlainAuthorJob',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Jobs/PlainAuthorJob.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "queued" job for the module', function () {
+ $this->artisan('module:make:job', [
+ 'name' => 'QueuedAuthorJob',
+ 'module' => 'Author',
+ '--stub' => 'queued',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Jobs/QueuedAuthorJob.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/ListenerMakeCommandTest.php b/tests/Commands/Generators/ListenerMakeCommandTest.php
index 5f5fa1e..5b2b467 100644
--- a/tests/Commands/Generators/ListenerMakeCommandTest.php
+++ b/tests/Commands/Generators/ListenerMakeCommandTest.php
@@ -1,130 +1,38 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_plain_listener_file()
- {
- $code = $this->artisan('module:make:listener', [
- 'name' => 'MyAwesomePlainListener',
- 'module' => 'Article',
- '--stub' => 'plain',
- '--event' => 'Foo\\Bar/MyAwesomeEvent'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Listeners/MyAwesomePlainListener.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_queued_listener_file()
- {
- $code = $this->artisan('module:make:listener', [
- 'name' => 'MyAwesomeQueuedListener',
- 'module' => 'Article',
- '--stub' => 'queued',
- '--event' => 'Foo\\Bar/MyAwesomeEvent'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Listeners/MyAwesomeQueuedListener.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_plain_listener_file_with_content()
- {
- $code = $this->artisan('module:make:listener', [
- 'name' => 'Foo/Bar\\MyAwesomePlainListener',
- 'module' => 'Article',
- '--stub' => 'plain',
- '--event' => 'Foo\\Bar/MyAwesomeEvent'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Listeners/Foo/Bar/MyAwesomePlainListener.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_queued_listener_file_with_content()
- {
- $code = $this->artisan('module:make:listener', [
- 'name' => 'Foo/Bar\\MyAwesomeQueuedListener',
- 'module' => 'Article',
- '--stub' => 'queued',
- '--event' => 'Foo\\Bar/MyAwesomeEvent'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Listeners/Foo/Bar/MyAwesomeQueuedListener.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_plain_listener_file()
- {
- $this->app['config']->set('modules.generator.components.listener.path', 'Foo/Bar\\Listeners');
-
- $code = $this->artisan('module:make:listener', [
- 'name' => 'Baz\\Bat/MyAwesomePlainListener',
- 'module' => 'Article',
- '--stub' => 'plain',
- '--event' => 'Foo\\Bar/MyAwesomeEvent'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Listeners/Baz/Bat/MyAwesomePlainListener.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_plain_listener_file()
- {
- $this->app['config']->set('modules.generator.components.listener.namespace', 'Foo/Bar\\Listeners/');
-
- $code = $this->artisan('module:make:listener', [
- 'name' => 'Baz\\Bat/MyAwesomePlainListener',
- 'module' => 'Article',
- '--stub' => 'plain',
- '--event' => 'Foo\\Bar/MyAwesomeEvent'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Listeners/Baz/Bat/MyAwesomePlainListener.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "plain" listener for the module', function () {
+ $this->artisan('module:make:listener', [
+ 'name' => 'PlainAuthorListener',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ '--event' => 'SomeAuthorEvent',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Listeners/PlainAuthorListener.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "queued" listener for the module', function () {
+ $this->artisan('module:make:listener', [
+ 'name' => 'QueuedAuthorListener',
+ 'module' => 'Author',
+ '--stub' => 'queued',
+ '--event' => 'SomeAuthorEvent',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Listeners/QueuedAuthorListener.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/MailMakeCommandTest.php b/tests/Commands/Generators/MailMakeCommandTest.php
index 4c8ee55..1c04001 100644
--- a/tests/Commands/Generators/MailMakeCommandTest.php
+++ b/tests/Commands/Generators/MailMakeCommandTest.php
@@ -1,124 +1,24 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_plain_mail_file()
- {
- $code = $this->artisan('module:make:mail', [
- 'name' => 'MyAwesomePlainMail',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Mails/MyAwesomePlainMail.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_queued_mail_file()
- {
- $code = $this->artisan('module:make:mail', [
- 'name' => 'MyAwesomeQueuedMail',
- 'module' => 'Article',
- '--stub' => 'queued'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Mails/MyAwesomeQueuedMail.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_plain_mail_file_with_content()
- {
- $code = $this->artisan('module:make:mail', [
- 'name' => 'Foo/Bar\\MyAwesomePlainMail',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Mails/Foo/Bar/MyAwesomePlainMail.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_queued_mail_file_with_content()
- {
- $code = $this->artisan('module:make:mail', [
- 'name' => 'Foo/Bar\\MyAwesomeQueuedMail',
- 'module' => 'Article',
- '--stub' => 'queued'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Mails/Foo/Bar/MyAwesomeQueuedMail.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_plain_mail_file()
- {
- $this->app['config']->set('modules.generator.components.mail.path', 'Foo/Bar\\Mails');
-
- $code = $this->artisan('module:make:mail', [
- 'name' => 'Baz\\Bat/MyAwesomePlainMail',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Mails/Baz/Bat/MyAwesomePlainMail.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_plain_mail_file()
- {
- $this->app['config']->set('modules.generator.components.mail.namespace', 'Foo/Bar\\Mails/');
-
- $code = $this->artisan('module:make:mail', [
- 'name' => 'Baz\\Bat/MyAwesomePlainMail',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Mails/Baz/Bat/MyAwesomePlainMail.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates mail for the module', function () {
+ $this->artisan('module:make:mail', [
+ 'name' => 'SomeAuthorMail',
+ 'module' => 'Author',
+ '--subject' => 'Some testing subject',
+ '--view' => 'author.mail.some-view',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Mails/SomeAuthorMail.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/MiddlewareMakeCommandTest.php b/tests/Commands/Generators/MiddlewareMakeCommandTest.php
index 8c5b7a2..4ea6e63 100644
--- a/tests/Commands/Generators/MiddlewareMakeCommandTest.php
+++ b/tests/Commands/Generators/MiddlewareMakeCommandTest.php
@@ -1,92 +1,22 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_middleware_file()
- {
- $code = $this->artisan('module:make:middleware', [
- 'name' => 'MyAwesomeMiddleware',
- 'module' => 'Article',
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Middleware/MyAwesomeMiddleware.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_middleware_file_with_content()
- {
- $code = $this->artisan('module:make:middleware', [
- 'name' => 'Foo/Bar\\MyAwesomeMiddleware',
- 'module' => 'Article',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Middleware/Foo/Bar/MyAwesomeMiddleware.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_middleware_file()
- {
- $this->app['config']->set('modules.generator.components.middleware.path', 'Foo/Bar\\Middleware');
-
- $code = $this->artisan('module:make:middleware', [
- 'name' => 'Baz\\Bat/MyAwesomeMiddleware',
- 'module' => 'Article',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Middleware/Baz/Bat/MyAwesomeMiddleware.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_middleware_file()
- {
- $this->app['config']->set('modules.generator.components.middleware.namespace', 'Foo/Bar\\Middleware/');
-
- $code = $this->artisan('module:make:middleware', [
- 'name' => 'Baz\\Bat/MyAwesomeMiddleware',
- 'module' => 'Article',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Middleware/Baz/Bat/MyAwesomeMiddleware.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates middleware for the module', function () {
+ $this->artisan('module:make:middleware', [
+ 'name' => 'SomeAuthorMiddleware',
+ 'module' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Middleware/SomeAuthorMiddleware.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/MigrationMakeCommandTest.php b/tests/Commands/Generators/MigrationMakeCommandTest.php
index b83133a..431e612 100644
--- a/tests/Commands/Generators/MigrationMakeCommandTest.php
+++ b/tests/Commands/Generators/MigrationMakeCommandTest.php
@@ -1,169 +1,231 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_migration_file()
- {
- $code = $this->artisan('module:make:migration', [
- 'name' => 'create_posts_table',
- 'module' => 'Article'
- ]);
-
- $files = $this->finder->allFiles($this->modulePath . '/Data/Migrations');
-
- $this->assertCount(1, $files);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path()
- {
- $this->app['config']->set('modules.generator.components.migration.path', 'Foo/Bar\\Migrations');
-
- $code = $this->artisan('module:make:migration', [
- 'name' => 'create_posts_table',
- 'module' => 'Article'
- ]);
-
- $files = $this->finder->allFiles($this->modulePath . '/Foo/Bar/Migrations');
-
- $this->assertCount(1, $files);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_correct_create_migration_file_content()
- {
- $code = $this->artisan('module:make:migration', [
- 'name' => 'create_posts_table',
+use Illuminate\Support\Carbon;
+
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ realpath(__DIR__ . '/../../fixtures/stubs/modules/valid/article'),
+ ], $this->app->basePath('/modules'));
+
+ $date = Carbon::parse('2024-01-01');
+ $this->travelTo($date);
+ $this->dateStamp = $date->format('Y_m_d_His_');
+});
+
+it('generates "plain" migration for the module', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'some_plain_migration',
+ 'module' => 'Article',
+ '--stub' => 'plain',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}some_plain_migration.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "plain" migration for the module if the stub is not recognized by name', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'some_plain_migration',
+ 'module' => 'Article',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}some_plain_migration.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "create" migration for the module', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'new_articles_table',
+ 'module' => 'Article',
+ '--stub' => 'create',
+ '--fields' => 'title:string,excerpt:text,content:text,belongsTo:user:id:users',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}new_articles_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "create" migration for the module without fields', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'new_articles_table',
+ 'module' => 'Article',
+ '--stub' => 'create',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}new_articles_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('automatically detects and generates "create" migration for the module', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'create_articles_table',
+ 'module' => 'Article',
+ '--fields' => 'title:string,excerpt:text,content:text,belongsTo:user:id:users',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}create_articles_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "add" migration for the module', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'modify_articles_table',
+ 'module' => 'Article',
+ '--stub' => 'add',
+ '--fields' => 'title:string,excerpt:text,belongsTo:user:id:users',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}modify_articles_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "add" migration for the module without fields', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'modify_articles_table',
+ 'module' => 'Article',
+ '--stub' => 'add',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}modify_articles_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('automatically detects and generates "add" migration for the module', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'add_title_to_articles_table',
+ 'module' => 'Article',
+ '--fields' => 'title:string',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}add_title_to_articles_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "delete" migration for the module', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'modify_articles_table',
+ 'module' => 'Article',
+ '--stub' => 'delete',
+ '--fields' => 'title:string,excerpt:text,belongsTo:user:id:users',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}modify_articles_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "delete" migration for the module without fields', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'modify_articles_table',
+ 'module' => 'Article',
+ '--stub' => 'delete',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}modify_articles_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('automatically detects and generates "delete" migration for the module', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'delete_title_from_articles_table',
+ 'module' => 'Article',
+ '--fields' => 'title:string',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}delete_title_from_articles_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "pivot" migration for the module', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'create_article_author_table',
+ 'module' => 'Article',
+ '--stub' => 'pivot',
+ ])
+ ->expectsQuestion('Enter the name of first table', 'articles')
+ ->expectsQuestion('Enter the name of second table', 'authors')
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath("/modules/article/database/migrations/{$this->dateStamp}create_article_author_table.php");
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+describe('table name validation', function () {
+ it('rejects invalid table names with special characters', function () {
+ // Use a migration name that doesn't auto-detect the table name,
+ // so we can enter an invalid one via the prompt
+ $this->artisan('module:make:migration', [
+ 'name' => 'modify_something',
'module' => 'Article',
- '--fields' => 'title:string,excerpt:text,content:text,belongsTo:user:id:users'
- ]);
-
- $files = $this->finder->allFiles($this->modulePath . '/Data/Migrations');
- $fileName = $files[0]->getRelativePathname();
- $file = $this->finder->get($this->modulePath . '/Data/Migrations/' . $fileName);
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_correct_add_migration_file_content()
- {
- $code = $this->artisan('module:make:migration', [
- 'name' => 'add_title_to_posts_table',
+ '--stub' => 'create',
+ ])
+ ->expectsQuestion('Enter the table name', 'invalid-table')
+ ->expectsOutputToContain('not valid')
+ ->assertFailed();
+ });
+
+ it('rejects invalid table names starting with a number', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'modify_something',
'module' => 'Article',
- '--fields' => 'title:string'
- ]);
-
- $files = $this->finder->allFiles($this->modulePath . '/Data/Migrations');
- $fileName = $files[0]->getRelativePathname();
- $file = $this->finder->get($this->modulePath . '/Data/Migrations/' . $fileName);
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_correct_delete_migration_file_content()
- {
- $code = $this->artisan('module:make:migration', [
- 'name' => 'remove_title_from_posts_table',
- 'module' => 'Article',
- '--fields' => 'title:string'
- ]);
-
- $files = $this->finder->allFiles($this->modulePath . '/Data/Migrations');
- $fileName = $files[0]->getRelativePathname();
- $file = $this->finder->get($this->modulePath . '/Data/Migrations/' . $fileName);
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_correct_pivot_migration_file_content()
- {
- $code = $this->artisan('module:make:migration', [
- 'name' => 'create_user_role_table',
+ '--stub' => 'create',
+ ])
+ ->expectsQuestion('Enter the table name', '123table')
+ ->expectsOutputToContain('not valid')
+ ->assertFailed();
+ });
+
+ it('rejects invalid pivot table names', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'create_article_author_table',
'module' => 'Article',
'--stub' => 'pivot',
- '-n' => true
- ]);
-
- $files = $this->finder->allFiles($this->modulePath . '/Data/Migrations');
- $fileName = $files[0]->getRelativePathname();
- $file = $this->finder->get($this->modulePath . '/Data/Migrations/' . $fileName);
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
-// public function it_generates_correct_pivot_migration_file_content_with_options()
-// {
-// $code = $this->artisan('module:make:migration', [
-// 'name' => 'create_user_role_table',
-// 'module' => 'Article',
-// '--stub' => 'pivot',
-// '--tableOne' => 'users',
-// '--tableTwo' => 'roles',
-// ]);
-//
-// $files = $this->finder->allFiles($this->modulePath . '/Data/Migrations');
-// $fileName = $files[0]->getRelativePathname();
-// $file = $this->finder->get($this->modulePath . '/Data/Migrations/' . $fileName);
-//
-// $this->assertMatchesSnapshot($file);
-// $this->assertSame(0, $code);
-// }
-
- /** @test */
- public function it_generates_correct_plain_migration_file_content()
- {
- $code = $this->artisan('module:make:migration', [
- 'name' => 'create_posts_table',
+ ])
+ ->expectsQuestion('Enter the name of first table', 'invalid-table')
+ ->expectsQuestion('Enter the name of second table', 'authors')
+ ->expectsOutputToContain('not valid')
+ ->assertFailed();
+ });
+
+ it('accepts valid table names', function () {
+ $this->artisan('module:make:migration', [
+ 'name' => 'create_valid_table_table',
'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $files = $this->finder->allFiles($this->modulePath . '/Data/Migrations');
- $fileName = $files[0]->getRelativePathname();
- $file = $this->finder->get($this->modulePath . '/Data/Migrations/' . $fileName);
+ '--stub' => 'create',
+ ])
+ ->assertSuccessful();
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+ $this->artisan('module:make:migration', [
+ 'name' => 'create__underscore_table_table',
+ 'module' => 'Article',
+ '--stub' => 'create',
+ '--force' => true,
+ ])
+ ->assertSuccessful();
+ });
+});
diff --git a/tests/Commands/Generators/ModelMakeCommandTest.php b/tests/Commands/Generators/ModelMakeCommandTest.php
index a7e374e..88d76f9 100644
--- a/tests/Commands/Generators/ModelMakeCommandTest.php
+++ b/tests/Commands/Generators/ModelMakeCommandTest.php
@@ -1,112 +1,36 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_plain_model_file()
- {
- $code = $this->artisan('module:make:model', [
- 'name' => 'MyAwesomePlainModel',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Models/MyAwesomePlainModel.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_plain_model_file_with_content()
- {
- $code = $this->artisan('module:make:model', [
- 'name' => 'Foo/Bar\\MyAwesomePlainModel',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Models/Foo/Bar/MyAwesomePlainModel.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_full_model_file_with_content()
- {
- $code = $this->artisan('module:make:model', [
- 'name' => 'Foo/Bar\\MyAwesomeFullModel',
- 'module' => 'Article',
- '--stub' => 'full',
- '--factory' => 'Bar\\Baz/Bat\\MyAwesomeFactory'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Models/Foo/Bar/MyAwesomeFullModel.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_plain_model_file()
- {
- $this->app['config']->set('modules.generator.components.model.path', 'Foo/Bar\\Models');
-
- $code = $this->artisan('module:make:model', [
- 'name' => 'Baz\\Bat/MyAwesomePlainModel',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Models/Baz/Bat/MyAwesomePlainModel.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_plain_model_file()
- {
- $this->app['config']->set('modules.generator.components.model.namespace', 'Foo/Bar\\Models/');
-
- $code = $this->artisan('module:make:model', [
- 'name' => 'Baz\\Bat/MyAwesomePlainModel',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Models/Baz/Bat/MyAwesomePlainModel.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates plain model for the module', function () {
+ $this->artisan('module:make:model', [
+ 'name' => 'AuthorEmail',
+ 'module' => 'Author',
+ ])
+ ->expectsQuestion('Enter the class name of the factory to be used in the model (optional)', '')
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Models/AuthorEmail.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates model with factory for the module', function () {
+ $this->artisan('module:make:model', [
+ 'name' => 'AuthorEmail',
+ 'module' => 'Author',
+ '--factory' => 'AuthorEmailFactory',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Models/AuthorEmail.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/ModuleMakeCommandTest.php b/tests/Commands/Generators/ModuleMakeCommandTest.php
index 9644398..8e66461 100644
--- a/tests/Commands/Generators/ModuleMakeCommandTest.php
+++ b/tests/Commands/Generators/ModuleMakeCommandTest.php
@@ -1,309 +1,119 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->repository = $this->app[RepositoryInterface::class];
- $this->activator = $this->app[ActivatorInterface::class];
- $this->moduleComponentPaths = [
- 'Actions/CreateArticleAction.php',
- 'Actions/UpdateArticleAction.php',
- 'Actions/DeleteArticleAction.php',
- 'Actions/ViewArticleAction.php',
- 'Actions/ListArticlesAction.php',
- 'Data/Factories/ArticleFactory.php',
- 'Data/Seeders/ArticlePermissionsSeeder_1.php',
- 'DTO/CreateArticleDTO.php',
- 'Models/Article.php',
- 'Policies/ArticlePolicy.php',
- 'Providers/ArticleServiceProvider.php',
- 'Providers/RouteServiceProvider.php',
- 'UI/API/QueryWizards/ArticleQueryWizard.php',
- 'UI/API/QueryWizards/ArticlesQueryWizard.php',
- 'UI/API/Resources/ArticleResource.php',
- 'UI/API/Requests/CreateArticleRequest.php',
- 'UI/API/Requests/UpdateArticleRequest.php',
- 'UI/API/Requests/DeleteArticleRequest.php',
- 'UI/API/Requests/ViewArticleRequest.php',
- 'UI/API/Requests/ListArticlesRequest.php',
- 'UI/API/Routes/v1/create_article.php',
- 'UI/API/Routes/v1/update_article.php',
- 'UI/API/Routes/v1/delete_article.php',
- 'UI/API/Routes/v1/view_article.php',
- 'UI/API/Routes/v1/list_articles.php',
- 'UI/API/Tests/CreateArticleTest.php',
- 'UI/API/Tests/UpdateArticleTest.php',
- 'UI/API/Tests/DeleteArticleTest.php',
- 'UI/API/Tests/ViewArticleTest.php',
- 'UI/API/Tests/ListArticlesTest.php',
- ];
- }
-
- protected function tearDown(): void
- {
- $this->finder->deleteDirectory($this->modulePath);
- if ($this->finder->isDirectory(base_path('app/Modules/ModuleName'))) {
- $this->finder->deleteDirectory(base_path('app/Modules/ModuleName'));
- }
- if ($this->finder->isDirectory(base_path('app/Modules/Blog'))) {
- $this->finder->deleteDirectory(base_path('app/Modules/Blog'));
- }
- $this->activator->reset();
-
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_module()
- {
- $code = $this->artisan('module:make', ['name' => 'Article']);
-
- $this->assertDirectoryExists($this->modulePath);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_module_folders()
- {
- $code = $this->artisan('module:make', ['name' => 'Article']);
-
- foreach (config('modules.generator.components') as $directory) {
- if ($directory['generate'] === true) {
- $this->assertDirectoryExists($this->modulePath . '/' . $directory['path']);
- }
- }
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_module_scaffold_files()
- {
- $code = $this->artisan('module:make', ['name' => 'Article']);
-
- $moduleJsonPath = $this->modulePath . '/module.json';
- $this->assertFileExists($moduleJsonPath);
- $this->assertMatchesSnapshot($this->finder->get($moduleJsonPath));
-
- $composerJsonPath = $this->modulePath . '/composer.json';
- $this->assertFileExists($composerJsonPath);
- $this->assertMatchesSnapshot($this->finder->get($composerJsonPath));
-
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_module_components()
- {
- $code = $this->artisan('module:make', ['name' => 'Article']);
-
- foreach ($this->moduleComponentPaths as $componentPath) {
- $path = $this->modulePath . '/' . $componentPath;
- $this->assertFileExists($path);
- $this->assertMatchesSnapshot($this->finder->get($path));
- }
-
- $migrationFiles = $this->finder->allFiles($this->modulePath . '/Data/Migrations');
- $this->assertCount(1, $migrationFiles);
- $this->assertMatchesSnapshot($migrationFiles[0]->getContents());
-
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_module_folder_using_studly_case()
- {
- $code = $this->artisan('module:make', ['name' => 'ModuleName']);
-
- $this->assertTrue($this->finder->exists(base_path('app/Modules/ModuleName')));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_module_namespace_using_studly_case()
- {
- $code = $this->artisan('module:make', ['name' => 'ModuleName']);
-
- $file = $this->finder->get(base_path('app/Modules/ModuleName') . '/Providers/ModuleNameServiceProvider.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_a_plain_module_with_no_components()
- {
- $code = $this->artisan('module:make', ['name' => 'ModuleName', '--plain' => true]);
-
- foreach ($this->moduleComponentPaths as $componentPath) {
- $path = $this->modulePath . '/' . $componentPath;
- $this->assertFileDoesNotExist($path);
- }
- $this->assertDirectoryDoesNotExist($this->modulePath . '/Data/Migrations');
-
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_outputs_error_when_module_exists()
- {
- $this->artisan('module:make', ['name' => 'Article']);
- $code = $this->artisan('module:make', ['name' => 'Article']);
-
- $expected = 'Module [Article] already exist!
-';
- $this->assertEquals($expected, Artisan::output());
- $this->assertSame(E_ERROR, $code);
- }
-
- /** @test */
- public function it_still_generates_module_if_it_exists_using_force_flag()
- {
- $this->artisan('module:make', ['name' => 'Article']);
- $code = $this->artisan('module:make', ['name' => 'Article', '--force' => true]);
-
- $output = Artisan::output();
-
- $notExpected = 'Module [Article] already exist!
-';
- $this->assertNotEquals($notExpected, $output);
- $this->assertTrue(Str::contains($output, 'Module [Article] created successfully.'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_ignore_component_folders_to_generate()
- {
- $this->app['config']->set('modules.generator.components.seeder', ['path' => 'Data/Seeders', 'generate' => false]);
- $this->app['config']->set('modules.generator.components.provider', ['path' => 'Providers', 'generate' => false]);
- $this->app['config']->set('modules.generator.components.api-controller', ['path' => 'UI/API/Controllers', 'generate' => false]);
-
- $code = $this->artisan('module:make', ['name' => 'Article']);
-
- $this->assertDirectoryDoesNotExist($this->modulePath . '/Data/Seeders');
- $this->assertDirectoryDoesNotExist($this->modulePath . '/Providers');
- $this->assertDirectoryDoesNotExist($this->modulePath . '/UI/API/Controllers');
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_enabled_module()
- {
- $code = $this->artisan('module:make', ['name' => 'Article']);
-
- $this->assertTrue($this->repository->isEnabled('Article'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_disabled_module_with_disabled_flag()
- {
- $code = $this->artisan('module:make', ['name' => 'Article', '--disabled' => true]);
-
- $this->assertTrue($this->repository->isDisabled('Article'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generes_module_with_new_provider_location()
- {
- $this->app['config']->set('modules.generator.components.provider', ['path' => 'Base/Providers', 'generate' => true]);
-
- $code = $this->artisan('module:make', ['name' => 'Article']);
-
- $this->assertDirectoryExists($this->modulePath . '/Base/Providers');
-
- $file = $this->finder->get($this->modulePath . '/module.json');
- $this->assertMatchesSnapshot($file);
-
- $file = $this->finder->get($this->modulePath . '/composer.json');
- $this->assertMatchesSnapshot($file);
-
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_set_custom_model()
- {
- $code = $this->artisan('module:make', ['name' => 'Blog', '--entity' => 'PostComment']);
-
- $modulePath = base_path('app/Modules/Blog');
- $moduleComponentPaths = [
- 'Actions/CreatePostCommentAction.php',
- 'Actions/UpdatePostCommentAction.php',
- 'Actions/DeletePostCommentAction.php',
- 'Actions/ViewPostCommentAction.php',
- 'Actions/ListPostCommentsAction.php',
- 'Data/Factories/PostCommentFactory.php',
- 'Data/Seeders/PostCommentPermissionsSeeder_1.php',
- 'DTO/CreatePostCommentDTO.php',
- 'Models/PostComment.php',
- 'Policies/PostCommentPolicy.php',
- 'Providers/BlogServiceProvider.php',
- 'Providers/RouteServiceProvider.php',
- 'UI/API/QueryWizards/PostCommentQueryWizard.php',
- 'UI/API/QueryWizards/PostCommentsQueryWizard.php',
- 'UI/API/Resources/PostCommentResource.php',
- 'UI/API/Requests/CreatePostCommentRequest.php',
- 'UI/API/Requests/UpdatePostCommentRequest.php',
- 'UI/API/Requests/DeletePostCommentRequest.php',
- 'UI/API/Requests/ViewPostCommentRequest.php',
- 'UI/API/Requests/ListPostCommentsRequest.php',
- 'UI/API/Routes/v1/create_post_comment.php',
- 'UI/API/Routes/v1/update_post_comment.php',
- 'UI/API/Routes/v1/delete_post_comment.php',
- 'UI/API/Routes/v1/view_post_comment.php',
- 'UI/API/Routes/v1/list_post_comments.php',
- 'UI/API/Tests/CreatePostCommentTest.php',
- 'UI/API/Tests/UpdatePostCommentTest.php',
- 'UI/API/Tests/DeletePostCommentTest.php',
- 'UI/API/Tests/ViewPostCommentTest.php',
- 'UI/API/Tests/ListPostCommentsTest.php',
- ];
-
- $moduleJsonPath = $modulePath . '/module.json';
- $this->assertFileExists($moduleJsonPath);
- $this->assertMatchesSnapshot($this->finder->get($moduleJsonPath));
-
- $composerJsonPath = $modulePath . '/composer.json';
- $this->assertFileExists($composerJsonPath);
- $this->assertMatchesSnapshot($this->finder->get($composerJsonPath));
-
- foreach ($moduleComponentPaths as $componentPath) {
- $path = $modulePath . '/' . $componentPath;
- $this->assertFileExists($path);
- $this->assertMatchesSnapshot($this->finder->get($path));
- }
-
- $migrationFiles = $this->finder->allFiles($modulePath . '/Data/Migrations');
- $this->assertCount(1, $migrationFiles);
- $this->assertMatchesSnapshot($migrationFiles[0]->getContents());
-
- $this->assertSame(0, $code);
- }
-}
+use Illuminate\Support\Carbon;
+use Laraneat\Modules\Support\Composer;
+
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->backupComposerJson();
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/article',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/empty',
+ __DIR__ . '/../../fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ $this->travelTo(Carbon::parse('2024-01-01'));
+});
+
+it('generates a "plain" module', function () {
+ $this->instance(Composer::class, $this->mockComposer(['updatePackages' => true]));
+ $this->artisan('module:make', [
+ 'name' => 'demo/article-comment',
+ '--preset' => 'plain',
+ '--entity' => 'ArticleComment',
+ ])
+ ->assertSuccessful();
+
+ assertMatchesFileSnapshot($this->app->basePath('/composer.json'));
+ assertsMatchesDirectorySnapshot($this->app->basePath('/modules/article-comment'));
+});
+
+it('generates a "base" module', function () {
+ $this->instance(Composer::class, $this->mockComposer(['updatePackages' => true]));
+ $this->artisan('module:make', [
+ 'name' => 'demo/article-comment',
+ '--preset' => 'base',
+ '--entity' => 'ArticleComment',
+ ])
+ ->expectsQuestion(
+ 'Enter the class name of the "Create permission action"',
+ 'Modules\\Authorization\\Actions\\CreatePermissionAction'
+ )
+ ->expectsQuestion(
+ 'Enter the class name of the "Create permission DTO"',
+ 'Modules\\Authorization\\DTO\\CreatePermissionDTO'
+ )
+ ->expectsQuestion(
+ 'Enter the class name of the "User model"',
+ 'Modules\\User\\Models\\User'
+ )
+ ->assertSuccessful();
+
+ assertMatchesFileSnapshot($this->app->basePath('/composer.json'));
+ assertsMatchesDirectorySnapshot($this->app->basePath('/modules/article-comment'));
+});
+
+it('generates a "api" module', function () {
+ $this->instance(Composer::class, $this->mockComposer(['updatePackages' => true]));
+ $this->artisan('module:make', [
+ 'name' => 'demo/article-comment',
+ '--preset' => 'api',
+ '--entity' => 'ArticleComment',
+ ])
+ ->expectsQuestion(
+ 'Enter the class name of the "Create permission action"',
+ 'Modules\\Authorization\\Actions\\CreatePermissionAction'
+ )
+ ->expectsQuestion(
+ 'Enter the class name of the "Create permission DTO"',
+ 'Modules\\Authorization\\DTO\\CreatePermissionDTO'
+ )
+ ->expectsQuestion(
+ 'Enter the class name of the "User model"',
+ 'Modules\\User\\Models\\User'
+ )
+ ->assertSuccessful();
+
+ assertMatchesFileSnapshot($this->app->basePath('/composer.json'));
+ assertsMatchesDirectorySnapshot($this->app->basePath('/modules/article-comment'));
+});
+
+it('displays an error message if the passed module name is not valid', function () {
+ $this->artisan('module:make', [
+ 'name' => '1foo',
+ '--preset' => 'plain',
+ '--entity' => 'Foo',
+ ])
+ ->expectsOutputToContain("The module name passed is not valid!")
+ ->assertFailed();
+
+ assertMatchesFileSnapshot($this->app->basePath('/composer.json'));
+});
+
+it('displays an error message when a module with the same package name already exists', function () {
+ $this->artisan('module:make', [
+ 'name' => 'laraneat/article',
+ '--preset' => 'plain',
+ '--entity' => 'Article',
+ ])
+ ->expectsOutputToContain("Module 'laraneat/article' already exist!")
+ ->assertFailed();
+
+ assertMatchesFileSnapshot($this->app->basePath('/composer.json'));
+});
+
+it('displays an error message when a module with the same folder name already exists', function () {
+ $this->artisan('module:make', [
+ 'name' => 'demo/article',
+ '--preset' => 'plain',
+ '--entity' => 'Article',
+ ])
+ ->expectsOutputToContain("File already exists")
+ ->assertFailed();
+
+ assertMatchesFileSnapshot($this->app->basePath('/composer.json'));
+});
diff --git a/tests/Commands/Generators/NotificationMakeCommandTest.php b/tests/Commands/Generators/NotificationMakeCommandTest.php
index ea62571..b659a9c 100644
--- a/tests/Commands/Generators/NotificationMakeCommandTest.php
+++ b/tests/Commands/Generators/NotificationMakeCommandTest.php
@@ -1,124 +1,36 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_plain_notification_file()
- {
- $code = $this->artisan('module:make:notification', [
- 'name' => 'MyAwesomePlainNotification',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Notifications/MyAwesomePlainNotification.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_queued_notification_file()
- {
- $code = $this->artisan('module:make:notification', [
- 'name' => 'MyAwesomeQueuedNotification',
- 'module' => 'Article',
- '--stub' => 'queued'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Notifications/MyAwesomeQueuedNotification.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_plain_notification_file_with_content()
- {
- $code = $this->artisan('module:make:notification', [
- 'name' => 'Foo/Bar\\MyAwesomePlainNotification',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Notifications/Foo/Bar/MyAwesomePlainNotification.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_queued_notification_file_with_content()
- {
- $code = $this->artisan('module:make:notification', [
- 'name' => 'Foo/Bar\\MyAwesomeQueuedNotification',
- 'module' => 'Article',
- '--stub' => 'queued'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Notifications/Foo/Bar/MyAwesomeQueuedNotification.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_plain_notification_file()
- {
- $this->app['config']->set('modules.generator.components.notification.path', 'Foo/Bar\\Notifications');
-
- $code = $this->artisan('module:make:notification', [
- 'name' => 'Baz\\Bat/MyAwesomePlainNotification',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Notifications/Baz/Bat/MyAwesomePlainNotification.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_plain_notification_file()
- {
- $this->app['config']->set('modules.generator.components.notification.namespace', 'Foo/Bar\\Notifications/');
-
- $code = $this->artisan('module:make:notification', [
- 'name' => 'Baz\\Bat/MyAwesomePlainNotification',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Notifications/Baz/Bat/MyAwesomePlainNotification.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "plain" notification for the module', function () {
+ $this->artisan('module:make:notification', [
+ 'name' => 'PlainAuthorNotification',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Notifications/PlainAuthorNotification.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "queued" notification for the module', function () {
+ $this->artisan('module:make:notification', [
+ 'name' => 'QueuedAuthorNotification',
+ 'module' => 'Author',
+ '--stub' => 'queued',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Notifications/QueuedAuthorNotification.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/ObserverMakeCommandTest.php b/tests/Commands/Generators/ObserverMakeCommandTest.php
index 3dac581..77c64d8 100644
--- a/tests/Commands/Generators/ObserverMakeCommandTest.php
+++ b/tests/Commands/Generators/ObserverMakeCommandTest.php
@@ -1,96 +1,23 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_observer_file()
- {
- $code = $this->artisan('module:make:observer', [
- 'name' => 'MyAwesomeObserver',
- 'module' => 'Article',
- '--model' => 'Some\\Nested/Model'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Observers/MyAwesomeObserver.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_observer_file_with_content()
- {
- $code = $this->artisan('module:make:observer', [
- 'name' => 'Foo/Bar\\MyAwesomeObserver',
- 'module' => 'Article',
- '--model' => 'Some\\Nested/Model'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Observers/Foo/Bar/MyAwesomeObserver.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_observer_file()
- {
- $this->app['config']->set('modules.generator.components.observer.path', 'Foo/Bar\\Observers');
-
- $code = $this->artisan('module:make:observer', [
- 'name' => 'Baz\\Bat/MyAwesomeObserver',
- 'module' => 'Article',
- '--model' => 'Some\\Nested/Model'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Observers/Baz/Bat/MyAwesomeObserver.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_observer_file()
- {
- $this->app['config']->set('modules.generator.components.observer.namespace', 'Foo/Bar\\Observers/');
-
- $code = $this->artisan('module:make:observer', [
- 'name' => 'Baz\\Bat/MyAwesomeObserver',
- 'module' => 'Article',
- '--model' => 'Some\\Nested/Model'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Observers/Baz/Bat/MyAwesomeObserver.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates observer for the module', function () {
+ $this->artisan('module:make:observer', [
+ 'name' => 'SomeAuthorObserver',
+ 'module' => 'Author',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Observers/SomeAuthorObserver.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/PolicyMakeCommandTest.php b/tests/Commands/Generators/PolicyMakeCommandTest.php
index 4b24a50..bf926ae 100644
--- a/tests/Commands/Generators/PolicyMakeCommandTest.php
+++ b/tests/Commands/Generators/PolicyMakeCommandTest.php
@@ -1,126 +1,40 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_plain_policy_file()
- {
- $code = $this->artisan('module:make:policy', [
- 'name' => 'MyAwesomePlainPolicy',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Policies/MyAwesomePlainPolicy.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_full_policy_file()
- {
- $code = $this->artisan('module:make:policy', [
- 'name' => 'MyAwesomeFullPolicy',
- 'module' => 'Article',
- '--stub' => 'full',
- '--model' => 'Bar\\Bat/Baz\\MyAwesomeModel'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Policies/MyAwesomeFullPolicy.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_plain_policy_file_with_content()
- {
- $code = $this->artisan('module:make:policy', [
- 'name' => 'Foo/Bar\\MyAwesomePlainPolicy',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Policies/Foo/Bar/MyAwesomePlainPolicy.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_full_policy_file_with_content()
- {
- $code = $this->artisan('module:make:policy', [
- 'name' => 'Foo/Bar\\MyAwesomeFullPolicy',
- 'module' => 'Article',
- '--stub' => 'full',
- '--model' => 'Bar\\Bat/Baz\\MyAwesomeModel'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Policies/Foo/Bar/MyAwesomeFullPolicy.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_plain_policy_file()
- {
- $this->app['config']->set('modules.generator.components.policy.path', 'Foo/Bar\\Policies');
-
- $code = $this->artisan('module:make:policy', [
- 'name' => 'Baz\\Bat/MyAwesomePlainPolicy',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Policies/Baz/Bat/MyAwesomePlainPolicy.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_plain_policy_file()
- {
- $this->app['config']->set('modules.generator.components.policy.namespace', 'Foo/Bar\\Policies/');
-
- $code = $this->artisan('module:make:policy', [
- 'name' => 'Baz\\Bat/MyAwesomePlainPolicy',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Policies/Baz/Bat/MyAwesomePlainPolicy.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates plain policy for the module', function () {
+ $this->artisan('module:make:policy', [
+ 'name' => 'AuthorPolicy',
+ 'module' => 'Author',
+ ])
+ ->expectsQuestion('Enter the class name of the model to be used in the policy (optional)', '')
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Policies/AuthorPolicy.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates full policy for the module', function () {
+ $this->artisan('module:make:policy', [
+ 'name' => 'AuthorPolicy',
+ 'module' => 'Author',
+ '--model' => 'Author',
+ ])
+ ->expectsQuestion(
+ 'Enter the class name of the "User model"',
+ 'Modules\\User\\Models\\User'
+ )
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Policies/AuthorPolicy.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/ProviderMakeCommandTest.php b/tests/Commands/Generators/ProviderMakeCommandTest.php
index f616078..99a8c74 100644
--- a/tests/Commands/Generators/ProviderMakeCommandTest.php
+++ b/tests/Commands/Generators/ProviderMakeCommandTest.php
@@ -1,141 +1,77 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_provider_file(): void
- {
- $code = $this->artisan('module:make:provider', [
- 'name' => 'MyAwesomeProvider',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Providers/MyAwesomeProvider.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_provider_file_with_content(): void
- {
- $code = $this->artisan('module:make:provider', [
- 'name' => 'MyAwesomeProvider',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Providers/MyAwesomeProvider.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path(): void
- {
- $this->app['config']->set('modules.generator.components.provider.path', 'Foo/Bar\\NewProviders');
-
- $code = $this->artisan('module:make:provider', [
- 'name' => 'Baz\\Bat/MyAwesomeProvider',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/NewProviders/Baz/Bat/MyAwesomeProvider.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace(): void
- {
- $this->app['config']->set('modules.generator.components.provider.namespace', 'Foo/Bar\\NewProviders/');
-
- $code = $this->artisan('module:make:provider', [
- 'name' => 'Baz\\Bat/MyAwesomeProvider',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Providers/Baz/Bat/MyAwesomeProvider.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_module_provider_file(): void
- {
- $code = $this->artisan('module:make:provider', [
- 'name' => 'Baz\\Bat/MyAwesomeModuleProvider',
- 'module' => 'Article',
- '--stub' => 'module',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Providers/Baz/Bat/MyAwesomeModuleProvider.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_route_provider_file(): void
- {
- $code = $this->artisan('module:make:provider', [
- 'name' => 'Baz\\Bat/MyAwesomeRouteProvider',
- 'module' => 'Article',
- '--stub' => 'route',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Providers/Baz/Bat/MyAwesomeRouteProvider.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_event_provider_file(): void
- {
- $code = $this->artisan('module:make:provider', [
- 'name' => 'Baz\\Bat/MyAwesomeEventProvider',
- 'module' => 'Article',
- '--stub' => 'event',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Providers/Baz/Bat/MyAwesomeEventProvider.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "plain" provider for the module', function () {
+ $this->artisan('module:make:provider', [
+ 'name' => 'TestServiceProvider',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Providers/TestServiceProvider.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "module" provider for the module', function () {
+ $this->artisan('module:make:provider', [
+ 'name' => 'CustomModuleServiceProvider',
+ 'module' => 'Author',
+ '--stub' => 'module',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Providers/CustomModuleServiceProvider.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "event" provider for the module', function () {
+ $this->artisan('module:make:provider', [
+ 'name' => 'EventServiceProvider',
+ 'module' => 'Author',
+ '--stub' => 'event',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Providers/EventServiceProvider.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "route" provider for the module', function () {
+ $this->artisan('module:make:provider', [
+ 'name' => 'CustomRouteServiceProvider',
+ 'module' => 'Author',
+ '--stub' => 'route',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Providers/CustomRouteServiceProvider.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('registers provider in module composer.json', function () {
+ $this->artisan('module:make:provider', [
+ 'name' => 'CustomServiceProvider',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ ])
+ ->assertSuccessful();
+
+ $composerJsonPath = $this->app->basePath('/modules/author/composer.json');
+ $composerJson = json_decode(file_get_contents($composerJsonPath), true);
+
+ expect($composerJson['extra']['laravel']['providers'])
+ ->toContain('Modules\\Author\\Providers\\CustomServiceProvider');
+});
diff --git a/tests/Commands/Generators/QueryWizardMakeCommandTest.php b/tests/Commands/Generators/QueryWizardMakeCommandTest.php
index a7e0b4b..f2852f0 100644
--- a/tests/Commands/Generators/QueryWizardMakeCommandTest.php
+++ b/tests/Commands/Generators/QueryWizardMakeCommandTest.php
@@ -1,141 +1,36 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_query_wizard_file()
- {
- $code = $this->artisan('module:make:wizard', [
- 'name' => 'MyAwesomeQueryWizard',
- 'module' => 'Article',
- '-n' => true
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/API/QueryWizards/MyAwesomeQueryWizard.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_eloquent_query_wizard_file_with_content()
- {
- $code = $this->artisan('module:make:wizard', [
- 'name' => 'Foo/Bar\\MyAwesomeEloquentQueryWizard',
- 'module' => 'Article',
- '--stub' => 'eloquent'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/QueryWizards/Foo/Bar/MyAwesomeEloquentQueryWizard.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_scout_query_wizard_file_with_content()
- {
- $code = $this->artisan('module:make:wizard', [
- 'name' => 'Foo/Bar\\MyAwesomeScoutQueryWizard',
- 'module' => 'Article',
- '--stub' => 'scout'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/QueryWizards/Foo/Bar/MyAwesomeScoutQueryWizard.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_model_query_wizard_file_with_content()
- {
- $code = $this->artisan('module:make:wizard', [
- 'name' => 'Foo/Bar\\MyAwesomeModelQueryWizard',
- 'module' => 'Article',
- '--stub' => 'model'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/QueryWizards/Foo/Bar/MyAwesomeModelQueryWizard.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_elastic_query_wizard_file_with_content()
- {
- $code = $this->artisan('module:make:wizard', [
- 'name' => 'Foo/Bar\\MyAwesomeElasticQueryWizard',
- 'module' => 'Article',
- '--stub' => 'elastic'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/QueryWizards/Foo/Bar/MyAwesomeElasticQueryWizard.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_query_wizard_file()
- {
- $this->app['config']->set('modules.generator.components.api-query-wizard.path', 'Foo/Bar\\QueryWizards');
-
- $code = $this->artisan('module:make:wizard', [
- 'name' => 'Baz\\Bat/MyAwesomeQueryWizard',
- 'module' => 'Article',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/QueryWizards/Baz/Bat/MyAwesomeQueryWizard.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_query_wizard_file()
- {
- $this->app['config']->set('modules.generator.components.api-query-wizard.namespace', 'Foo/Bar\\QueryWizards/');
-
- $code = $this->artisan('module:make:wizard', [
- 'name' => 'Baz\\Bat/MyAwesomeQueryWizard',
- 'module' => 'Article',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/QueryWizards/Baz/Bat/MyAwesomeQueryWizard.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "eloquent" query-wizard for the module', function () {
+ $this->artisan('module:make:query-wizard', [
+ 'name' => 'AuthorsQueryWizard',
+ 'module' => 'Author',
+ '--stub' => 'eloquent',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/QueryWizards/AuthorsQueryWizard.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "model" query-wizard for the module', function () {
+ $this->artisan('module:make:query-wizard', [
+ 'name' => 'AuthorQueryWizard',
+ 'module' => 'Author',
+ '--stub' => 'model',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/QueryWizards/AuthorQueryWizard.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/RequestMakeCommandTest.php b/tests/Commands/Generators/RequestMakeCommandTest.php
index 218d82e..aed4fdf 100644
--- a/tests/Commands/Generators/RequestMakeCommandTest.php
+++ b/tests/Commands/Generators/RequestMakeCommandTest.php
@@ -1,363 +1,162 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_api_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'MyAwesomeApiRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/API/Requests/MyAwesomeApiRequest.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_api_request_file_with_content()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'MyAwesomeApiRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Requests/MyAwesomeApiRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_api_request()
- {
- $this->app['config']->set('modules.generator.components.api-request.path', 'Foo/Bar\\NewRequests');
-
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeApiRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/NewRequests/Baz/Bat/MyAwesomeApiRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_api_request()
- {
- $this->app['config']->set('modules.generator.components.api-request.namespace', 'Foo/Bar\\NewRequests/');
-
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeApiRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Requests/Baz/Bat/MyAwesomeApiRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_api_create_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeApiCreateRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'create',
- '--model' => 'Some/Nested\\Model',
- '--dto' => 'Foo/Bar\\TestDTO',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Requests/Baz/Bat/MyAwesomeApiCreateRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_throws_exception_when_classes_not_provided_for_api_create_request_file()
- {
- $this->expectException(InvalidOptionException::class);
-
- $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeApiCreateRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'create',
- '-n' => '',
- ]);
- }
-
- /** @test */
- public function it_can_generate_api_delete_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeApiDeleteRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'delete',
- '--model' => 'Some/Nested\\Model',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Requests/Baz/Bat/MyAwesomeApiDeleteRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_api_list_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeApiListRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'list',
- '--model' => 'Some/Nested\\Model',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Requests/Baz/Bat/MyAwesomeApiListRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_api_update_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeApiUpdateRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'update',
- '--model' => 'Some/Nested\\Model',
- '--dto' => 'Foo/Bar\\TestDTO',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Requests/Baz/Bat/MyAwesomeApiUpdateRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_throws_exception_when_classes_not_provided_for_api_update_request_file()
- {
- $this->expectException(InvalidOptionException::class);
-
- $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeApiUpdateRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'update',
- '-n' => '',
- ]);
- }
-
- /** @test */
- public function it_can_generate_api_view_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeApiViewRequest',
- 'module' => 'Article',
- '--ui' => 'api',
- '--stub' => 'view',
- '--model' => 'Some/Nested\\Model',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Requests/Baz/Bat/MyAwesomeApiViewRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_web_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'MyAwesomeWebRequest',
- 'module' => 'Article',
- '--ui' => 'web',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/WEB/Requests/MyAwesomeWebRequest.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_web_request_file_with_content()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'MyAwesomeWebRequest',
- 'module' => 'Article',
- '--ui' => 'web',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Requests/MyAwesomeWebRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_web_request()
- {
- $this->app['config']->set('modules.generator.components.web-request.path', 'Foo/Bar\\NewRequests');
-
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeWebRequest',
- 'module' => 'Article',
- '--ui' => 'web',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/NewRequests/Baz/Bat/MyAwesomeWebRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_web_request()
- {
- $this->app['config']->set('modules.generator.components.web-request.namespace', 'Foo/Bar\\NewRequests/');
-
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeWebRequest',
- 'module' => 'Article',
- '--ui' => 'web',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Requests/Baz/Bat/MyAwesomeWebRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_web_create_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeWebCreateRequest',
- 'module' => 'Article',
- '--ui' => 'web',
- '--stub' => 'create',
- '--model' => 'Some/Nested\\Model',
- '--dto' => 'Foo/Bar\\TestDTO',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Requests/Baz/Bat/MyAwesomeWebCreateRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_throws_exception_when_classes_not_provided_for_web_create_request_file()
- {
- $this->expectException(InvalidOptionException::class);
-
- $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeWebCreateRequest',
- 'module' => 'Article',
- '--ui' => 'web',
- '--stub' => 'create',
- '-n' => '',
- ]);
- }
-
- /** @test */
- public function it_can_generate_web_delete_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeWebDeleteRequest',
- 'module' => 'Article',
- '--ui' => 'web',
- '--stub' => 'delete',
- '--model' => 'Some/Nested\\Model',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Requests/Baz/Bat/MyAwesomeWebDeleteRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_web_update_request_file()
- {
- $code = $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeWebUpdateRequest',
- 'module' => 'Article',
- '--ui' => 'web',
- '--stub' => 'update',
- '--model' => 'Some/Nested\\Model',
- '--dto' => 'Foo/Bar\\TestDTO',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Requests/Baz/Bat/MyAwesomeWebUpdateRequest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_throws_exception_when_classes_not_provided_for_web_update_request_file()
- {
- $this->expectException(InvalidOptionException::class);
-
- $this->artisan('module:make:request', [
- 'name' => 'Baz\\Bat/MyAwesomeWebUpdateRequest',
- 'module' => 'Article',
- '--ui' => 'web',
- '--stub' => 'update',
- '-n' => '',
- ]);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "plain" web request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'PlainAuthorRequest',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ '--ui' => 'web',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/Requests/PlainAuthorRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "create" web request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'CreateAuthorRequest',
+ 'module' => 'Author',
+ '--stub' => 'create',
+ '--ui' => 'web',
+ '--dto' => 'CreateAuthorDTO',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/Requests/CreateAuthorRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "update" web request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'UpdateAuthorRequest',
+ 'module' => 'Author',
+ '--stub' => 'update',
+ '--ui' => 'web',
+ '--dto' => 'UpdateAuthorDTO',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/Requests/UpdateAuthorRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "delete" web request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'DeleteAuthorRequest',
+ 'module' => 'Author',
+ '--stub' => 'delete',
+ '--ui' => 'web',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/Requests/DeleteAuthorRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "plain" api request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'PlainAuthorRequest',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ '--ui' => 'api',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/Requests/PlainAuthorRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "create" api request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'CreateAuthorRequest',
+ 'module' => 'Author',
+ '--stub' => 'create',
+ '--ui' => 'api',
+ '--dto' => 'CreateAuthorDTO',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/Requests/CreateAuthorRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "update" api request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'UpdateAuthorRequest',
+ 'module' => 'Author',
+ '--stub' => 'update',
+ '--ui' => 'api',
+ '--dto' => 'UpdateAuthorDTO',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/Requests/UpdateAuthorRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "delete" api request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'DeleteAuthorRequest',
+ 'module' => 'Author',
+ '--stub' => 'delete',
+ '--ui' => 'api',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/Requests/DeleteAuthorRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "view" api request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'ViewAuthorRequest',
+ 'module' => 'Author',
+ '--stub' => 'view',
+ '--ui' => 'api',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/Requests/ViewAuthorRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "list" api request for the module', function () {
+ $this->artisan('module:make:request', [
+ 'name' => 'ListAuthorsRequest',
+ 'module' => 'Author',
+ '--stub' => 'list',
+ '--ui' => 'api',
+ '--model' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/Requests/ListAuthorsRequest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/ResourceMakeCommandTest.php b/tests/Commands/Generators/ResourceMakeCommandTest.php
index 425a654..8894423 100644
--- a/tests/Commands/Generators/ResourceMakeCommandTest.php
+++ b/tests/Commands/Generators/ResourceMakeCommandTest.php
@@ -1,111 +1,36 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_resource_file()
- {
- $code = $this->artisan('module:make:resource', [
- 'name' => 'MyAwesomeResource',
- 'module' => 'Article',
- '-n' => true
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/API/Resources/MyAwesomeResource.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_single_resource_file_with_content()
- {
- $code = $this->artisan('module:make:resource', [
- 'name' => 'Foo/Bar\\MyAwesomeSingleResource',
- 'module' => 'Article',
- '--stub' => 'single'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Resources/Foo/Bar/MyAwesomeSingleResource.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_collection_resource_file_with_content()
- {
- $code = $this->artisan('module:make:resource', [
- 'name' => 'Foo/Bar\\MyAwesomeCollectionResource',
- 'module' => 'Article',
- '--stub' => 'collection'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Resources/Foo/Bar/MyAwesomeCollectionResource.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_resource_file()
- {
- $this->app['config']->set('modules.generator.components.api-resource.path', 'Foo/Bar\\Resources');
-
- $code = $this->artisan('module:make:resource', [
- 'name' => 'Baz\\Bat/MyAwesomeResource',
- 'module' => 'Article',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Resources/Baz/Bat/MyAwesomeResource.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_resource_file()
- {
- $this->app['config']->set('modules.generator.components.api-resource.namespace', 'Foo/Bar\\Resources/');
-
- $code = $this->artisan('module:make:resource', [
- 'name' => 'Baz\\Bat/MyAwesomeResource',
- 'module' => 'Article',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Resources/Baz/Bat/MyAwesomeResource.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "single" resource for the module', function () {
+ $this->artisan('module:make:resource', [
+ 'name' => 'AuthorResource',
+ 'module' => 'Author',
+ '--stub' => 'single',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/Resources/AuthorResource.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "collection" resource for the module', function () {
+ $this->artisan('module:make:resource', [
+ 'name' => 'AuthorResourceCollection',
+ 'module' => 'Author',
+ '--stub' => 'collection',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/Resources/AuthorResourceCollection.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/RouteMakeCommandTest.php b/tests/Commands/Generators/RouteMakeCommandTest.php
index b6bd14d..13d8c46 100644
--- a/tests/Commands/Generators/RouteMakeCommandTest.php
+++ b/tests/Commands/Generators/RouteMakeCommandTest.php
@@ -1,338 +1,214 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_route_file()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_route',
- 'module' => 'Article',
- '--url' => 'some/route',
- '-n' => true
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/API/Routes/nested/some_route.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_route_file_with_content()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_route',
- 'module' => 'Article',
- '--url' => 'some/route',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Routes/nested/some_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_route_file()
- {
- $this->app['config']->set('modules.generator.components.api-route.path', 'Foo/Bar\\Routes');
-
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_route',
- 'module' => 'Article',
- '--url' => 'some/route',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Routes/nested/some_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_recognized_view_route()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/v1/view_posts',
- 'module' => 'Article',
- '--url' => 'posts/{post}',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Routes/v1/view_posts.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_api_route_with_get_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_get_route',
- 'module' => 'Article',
- '--ui' => 'api',
- '--url' => 'some/get/route',
- '--method' => 'get',
- '--name' => 'api.nested.some_get_route',
- '--action' => 'SomeGetAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Routes/nested/some_get_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_api_route_with_post_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_post_route',
- 'module' => 'Article',
- '--ui' => 'api',
- '--url' => 'some/post/route',
- '--method' => 'post',
- '--name' => 'api.nested.some_post_route',
- '--action' => 'SomePostAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Routes/nested/some_post_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_api_route_with_put_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_put_route',
- 'module' => 'Article',
- '--ui' => 'api',
- '--url' => 'some/put/route',
- '--method' => 'put',
- '--name' => 'api.nested.some_put_route',
- '--action' => 'SomePutAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Routes/nested/some_put_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_api_route_with_patch_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_patch_route',
- 'module' => 'Article',
- '--ui' => 'api',
- '--url' => 'some/patch/route',
- '--method' => 'patch',
- '--name' => 'api.nested.some_patch_route',
- '--action' => 'SomePatchAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Routes/nested/some_patch_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_api_route_with_delete_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_delete_route',
- 'module' => 'Article',
- '--ui' => 'api',
- '--url' => 'some/delete/route',
- '--method' => 'delete',
- '--name' => 'api.nested.some_delete_route',
- '--action' => 'SomeDeleteAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Routes/nested/some_delete_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_api_route_with_options_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_options_route',
- 'module' => 'Article',
- '--ui' => 'api',
- '--url' => 'some/options/route',
- '--method' => 'options',
- '--name' => 'api.nested.some_options_route',
- '--action' => 'SomeOptionsAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Routes/nested/some_options_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_web_route_with_get_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_get_route',
- 'module' => 'Article',
- '--ui' => 'web',
- '--url' => 'some/get/route',
- '--method' => 'get',
- '--name' => 'web.nested.some_get_route',
- '--action' => 'SomeGetAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Routes/nested/some_get_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_web_route_with_post_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_post_route',
- 'module' => 'Article',
- '--ui' => 'web',
- '--url' => 'some/post/route',
- '--method' => 'post',
- '--name' => 'web.nested.some_post_route',
- '--action' => 'SomePostAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Routes/nested/some_post_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_web_route_with_put_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_put_route',
- 'module' => 'Article',
- '--ui' => 'web',
- '--url' => 'some/put/route',
- '--method' => 'put',
- '--name' => 'web.nested.some_put_route',
- '--action' => 'SomePutAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Routes/nested/some_put_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_web_route_with_patch_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_patch_route',
- 'module' => 'Article',
- '--ui' => 'web',
- '--url' => 'some/patch/route',
- '--method' => 'patch',
- '--name' => 'web.nested.some_patch_route',
- '--action' => 'SomePatchAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Routes/nested/some_patch_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_web_route_with_delete_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_delete_route',
- 'module' => 'Article',
- '--ui' => 'web',
- '--url' => 'some/delete/route',
- '--method' => 'delete',
- '--name' => 'web.nested.some_delete_route',
- '--action' => 'SomeDeleteAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Routes/nested/some_delete_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_web_route_with_options_method()
- {
- $code = $this->artisan('module:make:route', [
- 'name' => '/nested/some_options_route',
- 'module' => 'Article',
- '--ui' => 'web',
- '--url' => 'some/options/route',
- '--method' => 'options',
- '--name' => 'web.nested.some_options_route',
- '--action' => 'SomeOptionsAction',
- '-n' => true
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Routes/nested/some_options_route.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "get" web route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'list_authors',
+ 'module' => 'Author',
+ '--ui' => 'web',
+ '--action' => 'ListAuthorsAction',
+ '--method' => 'get',
+ '--url' => 'authors',
+ '--name' => 'web.authors.list',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/routes/list_authors.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "post" web route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'create_author',
+ 'module' => 'Author',
+ '--ui' => 'web',
+ '--action' => 'CreateAuthorAction',
+ '--method' => 'post',
+ '--url' => 'authors',
+ '--name' => 'web.authors.create',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/routes/create_author.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "put" web route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'update_author',
+ 'module' => 'Author',
+ '--ui' => 'web',
+ '--action' => 'UpdateAuthorAction',
+ '--method' => 'put',
+ '--url' => 'authors/{author}',
+ '--name' => 'web.authors.update',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/routes/update_author.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "patch" web route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'update_author',
+ 'module' => 'Author',
+ '--ui' => 'web',
+ '--action' => 'UpdateAuthorAction',
+ '--method' => 'patch',
+ '--url' => 'authors/{author}',
+ '--name' => 'web.authors.update',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/routes/update_author.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "delete" web route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'delete_author',
+ 'module' => 'Author',
+ '--ui' => 'web',
+ '--action' => 'DeleteAuthorAction',
+ '--method' => 'delete',
+ '--url' => 'authors/{author}',
+ '--name' => 'web.authors.delete',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/routes/delete_author.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "options" web route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'options_authors',
+ 'module' => 'Author',
+ '--ui' => 'web',
+ '--action' => 'ListAuthorsAction',
+ '--method' => 'options',
+ '--url' => 'authors',
+ '--name' => 'web.authors.options',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/WEB/routes/options_authors.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "get" api route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'list_authors',
+ 'module' => 'Author',
+ '--ui' => 'api',
+ '--action' => 'ListAuthorsAction',
+ '--method' => 'get',
+ '--url' => 'authors',
+ '--name' => 'web.authors.list',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/routes/list_authors.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "post" api route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'create_author',
+ 'module' => 'Author',
+ '--ui' => 'api',
+ '--action' => 'CreateAuthorAction',
+ '--method' => 'post',
+ '--url' => 'authors',
+ '--name' => 'api.authors.create',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/routes/create_author.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "put" api route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'update_author',
+ 'module' => 'Author',
+ '--ui' => 'api',
+ '--action' => 'UpdateAuthorAction',
+ '--method' => 'put',
+ '--url' => 'authors/{author}',
+ '--name' => 'api.authors.update',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/routes/update_author.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "patch" api route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'update_author',
+ 'module' => 'Author',
+ '--ui' => 'api',
+ '--action' => 'UpdateAuthorAction',
+ '--method' => 'patch',
+ '--url' => 'authors/{author}',
+ '--name' => 'api.authors.update',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/routes/update_author.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "delete" api route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'delete_author',
+ 'module' => 'Author',
+ '--ui' => 'api',
+ '--action' => 'DeleteAuthorAction',
+ '--method' => 'delete',
+ '--url' => 'authors/{author}',
+ '--name' => 'api.authors.delete',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/routes/delete_author.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "options" api route for the module', function () {
+ $this->artisan('module:make:route', [
+ 'name' => 'options_authors',
+ 'module' => 'Author',
+ '--ui' => 'api',
+ '--action' => 'ListAuthorsAction',
+ '--method' => 'options',
+ '--url' => 'authors',
+ '--name' => 'api.authors.options',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/UI/API/routes/options_authors.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/RuleMakeCommandTest.php b/tests/Commands/Generators/RuleMakeCommandTest.php
index 9c3e690..7ff2d59 100644
--- a/tests/Commands/Generators/RuleMakeCommandTest.php
+++ b/tests/Commands/Generators/RuleMakeCommandTest.php
@@ -1,92 +1,22 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_rule_file()
- {
- $code = $this->artisan('module:make:rule', [
- 'name' => 'MyAwesomeRule',
- 'module' => 'Article',
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Rules/MyAwesomeRule.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_rule_file_with_content()
- {
- $code = $this->artisan('module:make:rule', [
- 'name' => 'Foo/Bar\\MyAwesomeRule',
- 'module' => 'Article',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Rules/Foo/Bar/MyAwesomeRule.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_rule_file()
- {
- $this->app['config']->set('modules.generator.components.rule.path', 'Foo/Bar\\Rules');
-
- $code = $this->artisan('module:make:rule', [
- 'name' => 'Baz\\Bat/MyAwesomeRule',
- 'module' => 'Article',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Rules/Baz/Bat/MyAwesomeRule.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_rule_file()
- {
- $this->app['config']->set('modules.generator.components.rule.namespace', 'Foo/Bar\\Rules/');
-
- $code = $this->artisan('module:make:rule', [
- 'name' => 'Baz\\Bat/MyAwesomeRule',
- 'module' => 'Article',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Rules/Baz/Bat/MyAwesomeRule.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates rule for the module', function () {
+ $this->artisan('module:make:rule', [
+ 'name' => 'SomeAuthorRule',
+ 'module' => 'Author',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/src/Rules/SomeAuthorRule.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/SeederMakeCommandTest.php b/tests/Commands/Generators/SeederMakeCommandTest.php
index a66cec7..4873e25 100644
--- a/tests/Commands/Generators/SeederMakeCommandTest.php
+++ b/tests/Commands/Generators/SeederMakeCommandTest.php
@@ -1,126 +1,45 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_generates_plain_seeder_file()
- {
- $code = $this->artisan('module:make:seeder', [
- 'name' => 'MyAwesomePlainSeeder',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Data/Seeders/MyAwesomePlainSeeder.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generates_permissions_seeder_file()
- {
- $code = $this->artisan('module:make:seeder', [
- 'name' => 'MyAwesomePermissionsSeeder',
- 'module' => 'Article',
- '--stub' => 'permissions',
- '--model' => 'Bar\\Bat/Baz\\MyAwesomeModel'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Data/Seeders/MyAwesomePermissionsSeeder.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_plain_seeder_file_with_content()
- {
- $code = $this->artisan('module:make:seeder', [
- 'name' => 'Foo/Bar\\MyAwesomePlainSeeder',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Data/Seeders/Foo/Bar/MyAwesomePlainSeeder.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_permissions_seeder_file_with_content()
- {
- $code = $this->artisan('module:make:seeder', [
- 'name' => 'Foo/Bar\\MyAwesomePermissionsSeeder',
- 'module' => 'Article',
- '--stub' => 'permissions',
- '--model' => 'Bar\\Bat/Baz\\MyAwesomeModel'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Data/Seeders/Foo/Bar/MyAwesomePermissionsSeeder.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_plain_seeder_file()
- {
- $this->app['config']->set('modules.generator.components.seeder.path', 'Foo/Bar\\Seeders');
-
- $code = $this->artisan('module:make:seeder', [
- 'name' => 'Baz\\Bat/MyAwesomePlainSeeder',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/Seeders/Baz/Bat/MyAwesomePlainSeeder.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_plain_seeder_file()
- {
- $this->app['config']->set('modules.generator.components.seeder.namespace', 'Foo/Bar\\Seeders/');
-
- $code = $this->artisan('module:make:seeder', [
- 'name' => 'Baz\\Bat/MyAwesomePlainSeeder',
- 'module' => 'Article',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Data/Seeders/Baz/Bat/MyAwesomePlainSeeder.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "plain" seeder for the module', function () {
+ $this->artisan('module:make:seeder', [
+ 'name' => 'AuthorsSeeder',
+ 'module' => 'Author',
+ '--stub' => 'plain',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/database/seeders/AuthorsSeeder.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates "permissions" seeder for the module', function () {
+ $this->artisan('module:make:seeder', [
+ 'name' => 'AuthorPermissionsSeeder',
+ 'module' => 'Author',
+ '--stub' => 'permissions',
+ '--model' => 'Author',
+ ])
+ ->expectsQuestion(
+ 'Enter the class name of the "Create permission action"',
+ 'Modules\\Authorization\\Actions\\CreatePermissionAction'
+ )
+ ->expectsQuestion(
+ 'Enter the class name of the "Create permission DTO"',
+ 'Modules\\Authorization\\DTO\\CreatePermissionDTO'
+ )
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/database/seeders/AuthorPermissionsSeeder.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/TestMakeCommandTest.php b/tests/Commands/Generators/TestMakeCommandTest.php
index 91af8be..e56875e 100644
--- a/tests/Commands/Generators/TestMakeCommandTest.php
+++ b/tests/Commands/Generators/TestMakeCommandTest.php
@@ -1,557 +1,209 @@
modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article', '--plain' => true]);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- // Type: Unit
-
- /** @test */
- public function it_generate_unit_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeUnitTest',
- 'module' => 'Article',
- '--type' => 'unit',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Tests/Unit/MyAwesomeUnitTest.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_unit_test_file_with_content()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeUnitTest',
- 'module' => 'Article',
- '--type' => 'unit',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Tests/Unit/MyAwesomeUnitTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_unit_test()
- {
- $this->app['config']->set('modules.generator.components.unit-test.path', 'Foo/Bar\\NewTests');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeUnitTest',
- 'module' => 'Article',
- '--type' => 'unit',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/NewTests/Baz/Bat/MyAwesomeUnitTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_unit_test()
- {
- $this->app['config']->set('modules.generator.components.unit-test.namespace', 'Foo/Bar\\NewTests/');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeUnitTest',
- 'module' => 'Article',
- '--type' => 'unit',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Tests/Unit/Baz/Bat/MyAwesomeUnitTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- // Type: Feature
-
- /** @test */
- public function it_generate_feature_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeFeatureTest',
- 'module' => 'Article',
- '--type' => 'feature',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/Tests/Feature/MyAwesomeFeatureTest.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_feature_test_file_with_content()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeFeatureTest',
- 'module' => 'Article',
- '--type' => 'feature',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Tests/Feature/MyAwesomeFeatureTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_feature_test()
- {
- $this->app['config']->set('modules.generator.components.feature-test.path', 'Foo/Bar\\NewTests');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeFeatureTest',
- 'module' => 'Article',
- '--type' => 'feature',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/NewTests/Baz/Bat/MyAwesomeFeatureTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_feature_test()
- {
- $this->app['config']->set('modules.generator.components.feature-test.namespace', 'Foo/Bar\\NewTests/');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeFeatureTest',
- 'module' => 'Article',
- '--type' => 'feature',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Tests/Feature/Baz/Bat/MyAwesomeFeatureTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- // Type: CLI
-
- /** @test */
- public function it_generate_cli_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeCliTest',
- 'module' => 'Article',
- '--type' => 'cli',
- '--stub' => 'plain'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/CLI/Tests/MyAwesomeCliTest.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_cli_test_file_with_content()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeCliTest',
- 'module' => 'Article',
- '--type' => 'cli',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/CLI/Tests/MyAwesomeCliTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_cli_test()
- {
- $this->app['config']->set('modules.generator.components.cli-test.path', 'Foo/Bar\\NewTests');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeCliTest',
- 'module' => 'Article',
- '--type' => 'cli',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/NewTests/Baz/Bat/MyAwesomeCliTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_cli_test()
- {
- $this->app['config']->set('modules.generator.components.cli-test.namespace', 'Foo/Bar\\NewTests/');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeCliTest',
- 'module' => 'Article',
- '--type' => 'cli',
- '--stub' => 'plain'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/CLI/Tests/Baz/Bat/MyAwesomeCliTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- // Type: API
-
- /** @test */
- public function it_generate_api_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeApiTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'plain',
- '--route' => 'some.api.url'
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/API/Tests/MyAwesomeApiTest.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_api_test_file_with_content()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeApiTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'plain',
- '--route' => 'some.api.url'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Tests/MyAwesomeApiTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_api_test()
- {
- $this->app['config']->set('modules.generator.components.api-test.path', 'Foo/Bar\\NewTests');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeApiTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'plain',
- '--route' => 'some.api.url'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/NewTests/Baz/Bat/MyAwesomeApiTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_api_test()
- {
- $this->app['config']->set('modules.generator.components.api-test.namespace', 'Foo/Bar\\NewTests/');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeApiTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'plain',
- '--route' => 'some.api.url'
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Tests/Baz/Bat/MyAwesomeApiTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_api_create_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeApiCreateTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'create',
- '--route' => 'some.api.url',
- '--model' => 'Some/Nested\\SomeTestModel',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Tests/Baz/Bat/MyAwesomeApiCreateTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_throws_exception_when_classes_not_provided_for_api_create_test_file()
- {
- $this->expectException(InvalidOptionException::class);
-
- $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeApiCreateTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'create',
- '--route' => 'some.api.url',
- '-n' => true,
- ]);
- }
-
- /** @test */
- public function it_can_generate_api_delete_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeApiDeleteTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'delete',
- '--route' => 'some.api.url',
- '--model' => 'Some/Nested\\SomeTestModel',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Tests/Baz/Bat/MyAwesomeApiDeleteTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_api_list_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeApiListTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'list',
- '--route' => 'some.api.url',
- '--model' => 'Some/Nested\\SomeTestModel',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Tests/Baz/Bat/MyAwesomeApiListTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_api_update_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeApiUpdateTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'update',
- '--route' => 'some.api.url',
- '--model' => 'Some/Nested\\SomeTestModel',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Tests/Baz/Bat/MyAwesomeApiUpdateTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_api_view_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeApiViewTest',
- 'module' => 'Article',
- '--type' => 'api',
- '--stub' => 'view',
- '--route' => 'some.api.url',
- '--model' => 'Some/Nested\\SomeTestModel',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/API/Tests/Baz/Bat/MyAwesomeApiViewTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- // Type: WEB
-
- /** @test */
- public function it_generate_web_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeWebTest',
- 'module' => 'Article',
- '--type' => 'web',
- '--stub' => 'plain',
- '--route' => 'some.web.url',
- ]);
-
- $this->assertTrue(is_file($this->modulePath . '/UI/WEB/Tests/MyAwesomeWebTest.php'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_generated_correct_web_test_file_with_content()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'MyAwesomeWebTest',
- 'module' => 'Article',
- '--type' => 'web',
- '--stub' => 'plain',
- '--route' => 'some.web.url',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Tests/MyAwesomeWebTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_path_for_web_test()
- {
- $this->app['config']->set('modules.generator.components.web-test.path', 'Foo/Bar\\NewTests');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeWebTest',
- 'module' => 'Article',
- '--type' => 'web',
- '--stub' => 'plain',
- '--route' => 'some.web.url',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/Foo/Bar/NewTests/Baz/Bat/MyAwesomeWebTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_change_the_default_namespace_for_web_test()
- {
- $this->app['config']->set('modules.generator.components.web-test.namespace', 'Foo/Bar\\NewTests/');
-
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeWebTest',
- 'module' => 'Article',
- '--type' => 'web',
- '--stub' => 'plain',
- '--route' => 'some.web.url',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Tests/Baz/Bat/MyAwesomeWebTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_web_create_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeWebCreateTest',
- 'module' => 'Article',
- '--type' => 'web',
- '--stub' => 'create',
- '--route' => 'some.web.url',
- '--model' => 'Some/Nested\\SomeTestModel',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Tests/Baz/Bat/MyAwesomeWebCreateTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_throws_exception_when_classes_not_provided_for_web_create_test_file()
- {
- $this->expectException(InvalidOptionException::class);
-
- $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeWebCreateTest',
- 'module' => 'Article',
- '--type' => 'web',
- '--stub' => 'create',
- '--route' => 'some.web.url',
- '-n' => true,
- ]);
- }
-
- /** @test */
- public function it_can_generate_web_delete_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeWebDeleteTest',
- 'module' => 'Article',
- '--type' => 'web',
- '--stub' => 'delete',
- '--route' => 'some.web.url',
- '--model' => 'Some/Nested\\SomeTestModel',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Tests/Baz/Bat/MyAwesomeWebDeleteTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_can_generate_web_update_test_file()
- {
- $code = $this->artisan('module:make:test', [
- 'name' => 'Baz\\Bat/MyAwesomeWebUpdateTest',
- 'module' => 'Article',
- '--type' => 'web',
- '--stub' => 'update',
- '--route' => 'some.web.url',
- '--model' => 'Some/Nested\\SomeTestModel',
- ]);
-
- $file = $this->finder->get($this->modulePath . '/UI/WEB/Tests/Baz/Bat/MyAwesomeWebUpdateTest.php');
-
- $this->assertMatchesSnapshot($file);
- $this->assertSame(0, $code);
- }
-}
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+beforeEach(function () {
+ $this->setModules([
+ __DIR__ . '/../../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('generates "unit" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'ExampleTest',
+ 'module' => 'Author',
+ '--type' => 'unit',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/Unit/ExampleTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates plain "feature" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'ExampleTest',
+ 'module' => 'Author',
+ '--type' => 'feature',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/Feature/ExampleTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates plain "cli" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'ExampleTest',
+ 'module' => 'Author',
+ '--type' => 'cli',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/CLI/ExampleTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates plain "web" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'ExampleTest',
+ 'module' => 'Author',
+ '--type' => 'web',
+ '--stub' => 'plain',
+ '--model' => 'Author',
+ '--route' => 'web.authors.example',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/WEB/ExampleTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates create "web" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'CreateAuthorTest',
+ 'module' => 'Author',
+ '--type' => 'web',
+ '--stub' => 'create',
+ '--model' => 'Author',
+ '--route' => 'web.authors.create',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/WEB/CreateAuthorTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates update "web" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'UpdateAuthorTest',
+ 'module' => 'Author',
+ '--type' => 'web',
+ '--stub' => 'update',
+ '--model' => 'Author',
+ '--route' => 'web.authors.update',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/WEB/UpdateAuthorTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates delete "web" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'DeleteAuthorTest',
+ 'module' => 'Author',
+ '--type' => 'web',
+ '--stub' => 'delete',
+ '--model' => 'Author',
+ '--route' => 'web.authors.delete',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/WEB/DeleteAuthorTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates plain "api" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'ExampleTest',
+ 'module' => 'Author',
+ '--type' => 'api',
+ '--stub' => 'plain',
+ '--model' => 'Author',
+ '--route' => 'api.authors.example',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/API/ExampleTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates create "api" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'CreateAuthorTest',
+ 'module' => 'Author',
+ '--type' => 'api',
+ '--stub' => 'create',
+ '--model' => 'Author',
+ '--route' => 'api.authors.create',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/API/CreateAuthorTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates update "api" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'UpdateAuthorTest',
+ 'module' => 'Author',
+ '--type' => 'api',
+ '--stub' => 'update',
+ '--model' => 'Author',
+ '--route' => 'api.authors.update',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/API/UpdateAuthorTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates delete "api" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'DeleteAuthorTest',
+ 'module' => 'Author',
+ '--type' => 'api',
+ '--stub' => 'delete',
+ '--model' => 'Author',
+ '--route' => 'api.authors.delete',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/API/DeleteAuthorTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates list "api" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'ListAuthorsTest',
+ 'module' => 'Author',
+ '--type' => 'api',
+ '--stub' => 'list',
+ '--model' => 'Author',
+ '--route' => 'api.authors.list',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/API/ListAuthorsTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
+
+it('generates view "api" test for the module', function () {
+ $this->artisan('module:make:test', [
+ 'name' => 'ViewAuthorTest',
+ 'module' => 'Author',
+ '--type' => 'api',
+ '--stub' => 'view',
+ '--model' => 'Author',
+ '--route' => 'api.authors.view',
+ ])
+ ->assertSuccessful();
+
+ $filePath = $this->app->basePath('/modules/author/tests/UI/API/ViewAuthorTest.php');
+ assertFileExists($filePath);
+ assertMatchesFileSnapshot($filePath);
+});
diff --git a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_change_the_default_namespace__1.txt b/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_change_the_default_namespace__1.txt
deleted file mode 100644
index 63810d9..0000000
--- a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_change_the_default_namespace__1.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-all());
- }
-
- public function asController(TestRequest $request): JsonResponse
- {
- $testModel = $this->handle($request->toDTO());
-
- return (new TestResource($testModel))->created();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_delete_action_file__1.txt b/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_delete_action_file__1.txt
deleted file mode 100644
index 15d9e9c..0000000
--- a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_delete_action_file__1.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-delete();
- }
-
- public function asController(TestRequest $request, TestModel $testModel): JsonResponse
- {
- $this->handle($testModel);
-
- return $this->noContent();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_list_action_file__1.txt b/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_list_action_file__1.txt
deleted file mode 100644
index 5046d85..0000000
--- a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_list_action_file__1.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-build()
- ->jsonPaginate();
- }
-
- public function asController(TestRequest $request): ResourceCollection
- {
- return TestResource::collection($this->handle($request));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_update_action_file__1.txt b/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_update_action_file__1.txt
deleted file mode 100644
index 8210ded..0000000
--- a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_update_action_file__1.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-all();
-
- if (empty($data)) {
- throw new UpdateResourceFailedException();
- }
-
- $testModel->update($data);
-
- return $testModel;
- }
-
- public function asController(TestRequest $request, TestModel $testModel): TestResource
- {
- $testModel = $this->handle($testModel, $request->toDTO());
-
- return new TestResource($testModel);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_view_action_file__1.txt b/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_view_action_file__1.txt
deleted file mode 100644
index ea5bc46..0000000
--- a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_can_generate_view_action_file__1.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-build();
- }
-
- public function asController(TestRequest $request, TestModel $testModel): TestResource
- {
- return new TestResource($this->handle($request, $testModel));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_generated_correct_action_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_generated_correct_action_file_with_content__1.txt
deleted file mode 100644
index f3d22eb..0000000
--- a/tests/Commands/Generators/__snapshots__/ActionMakeCommandTest__it_generated_correct_action_file_with_content__1.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-can('view-post');
- }
-
- /**
- * Determine whether the user can view the model.
- */
- public function view(User $user, Post $post): bool
- {
- return $user->can('view-post');
- }
-
- /**
- * Determine whether the user can create models.
- */
- public function create(User $user): bool
- {
- return $user->can('create-post');
- }
-
- /**
- * Determine whether the user can update the model.
- */
- public function update(User $user, Post $post): bool
- {
- return $user->can('update-post');
- }
-
- /**
- * Determine whether the user can delete the model.
- */
- public function delete(User $user, Post $post): bool
- {
- return $user->can('delete-post');
- }
-
- /**
- * Determine whether the user can restore the model.
- */
- public function restore(User $user, Post $post): bool
- {
- return $user->can('delete-post');
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- */
- public function forceDelete(User $user, Post $post): bool
- {
- return $user->can('force-delete-post');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__13.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__13.txt
deleted file mode 100644
index dca9938..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__13.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-registerMigrations();
- // $this->registerTranslations();
- // $this->registerCommands();
- // $this->registerViews();
- }
-
- /**
- * Get the services provided by the provider.
- */
- public function provides(): array
- {
- return [];
- }
-
- /**
- * Register translations.
- */
- public function registerTranslations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/lang');
- $langPath = resource_path('lang/modules/' . $this->moduleKey);
-
- $this->loadTranslationsFrom($sourcePath, $this->moduleKey);
-
- $this->publishes([
- $sourcePath => $langPath,
- ], 'translations');
- }
-
- /**
- * Register views.
- */
- public function registerViews(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/views');
- $viewsPath = resource_path('views/modules/' . $this->moduleKey);
-
- $this->loadViewsFrom(
- array_merge($this->getPublishableViewPaths($this->moduleKey), [$sourcePath]),
- $this->moduleKey
- );
-
- $this->publishes([
- $sourcePath => $viewsPath
- ], 'views');
- }
-
- /**
- * Register migrations.
- */
- public function registerMigrations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Data/Migrations');
- $migrationsPath = database_path('migrations');
-
- $this->loadMigrationsFrom($sourcePath);
-
- $this->publishes([
- $sourcePath => $migrationsPath
- ], 'migrations');
- }
-
- /**
- * Register artisan commands.
- */
- public function registerCommands(): void
- {
- if ($this->app->runningInConsole()) {
- $this->loadCommands(module_path($this->moduleName, 'UI/CLI/Commands'));
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__15.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__15.txt
deleted file mode 100644
index 8ccf7a1..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__15.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__16.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__16.txt
deleted file mode 100644
index 8b3ca78..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__16.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__17.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__17.txt
deleted file mode 100644
index 0b53eb9..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__17.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__19.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__19.txt
deleted file mode 100644
index beac85c..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__19.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-route('post');
- return $post && Gate::check('update', $post);
- }
-
- public function toDTO(): UpdatePostDTO
- {
- return new UpdatePostDTO($this->validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__2.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__2.txt
deleted file mode 100644
index e2e845d..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__2.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "example/blog",
- "description": "",
- "authors": [
- {
- "name": "Example name",
- "email": "example@example.com"
- }
- ],
- "autoload": {
- "psr-4": {
- "App\\Modules\\Blog\\": ""
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__20.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__20.txt
deleted file mode 100644
index 647bf30..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__20.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('post');
- return $post && Gate::check('delete', $post);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__21.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__21.txt
deleted file mode 100644
index daed175..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__21.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('post');
- return $post && Gate::check('view', $post);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__22.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__22.txt
deleted file mode 100644
index 4180656..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__22.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-name('api.posts.create');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__24.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__24.txt
deleted file mode 100644
index 5698164..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__24.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.posts.update');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__25.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__25.txt
deleted file mode 100644
index 40418a7..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__25.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.posts.delete');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__26.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__26.txt
deleted file mode 100644
index f31859f..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__26.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.posts.view');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__27.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__27.txt
deleted file mode 100644
index 5f765e2..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__27.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.posts.list');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__28.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__28.txt
deleted file mode 100644
index 7c27c0b..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__28.txt
+++ /dev/null
@@ -1,58 +0,0 @@
- 'create-post',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_create_post(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.posts.create'), $data)
- ->assertCreated()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->has('id')
- ->whereAll($data)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(Post::class, $data);
- }
-
- public function test_create_post_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.posts.create'), $data)
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__29.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__29.txt
deleted file mode 100644
index cc3c50b..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__29.txt
+++ /dev/null
@@ -1,74 +0,0 @@
- 'update-post',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_update_post(): void
- {
- $this->getTestingUser();
-
- $post = Post::factory()->create();
-
- $data = $this->getTestData();
- $expectedData = array_merge($data, [
- 'id' => $post->getKey(),
- ]);
-
- $this->patchJson(route('api.posts.update', ['post' => $post->getKey()]), $data)
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(Post::class, $expectedData);
- }
-
- public function test_update_post_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $post = Post::factory()->create();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.posts.update', ['post' => $post->getKey()]), $data)
- ->assertForbidden();
- }
-
- public function test_update_non_existing_post(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.posts.update', ['post' => 7777]), $data)
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__3.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__3.txt
deleted file mode 100644
index 514b69d..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__3.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-all());
- }
-
- public function asController(CreatePostRequest $request): JsonResponse
- {
- $post = $this->handle($request->toDTO());
-
- return (new PostResource($post))->created();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__30.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__30.txt
deleted file mode 100644
index 8f7923b..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__30.txt
+++ /dev/null
@@ -1,51 +0,0 @@
- 'delete-post',
- 'roles' => '',
- ];
-
- public function test_delete_post(): void
- {
- $this->getTestingUser();
-
- $post = Post::factory()->create();
-
- $this->deleteJson(route('api.posts.delete', ['post' => $post->getKey()]))
- ->assertNoContent();
-
- $this->assertNull(Post::find($post->getKey()));
- }
-
- public function test_delete_post_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $post = Post::factory()->create();
-
- $this->deleteJson(route('api.posts.delete', ['post' => $post->getKey()]))
- ->assertForbidden();
- }
-
- public function test_delete_not_existing_post(): void
- {
- $this->getTestingUser();
-
- $this->deleteJson(route('api.posts.delete', ['post' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__31.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__31.txt
deleted file mode 100644
index e748d4c..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__31.txt
+++ /dev/null
@@ -1,57 +0,0 @@
- 'view-post',
- 'roles' => '',
- ];
-
- public function test_view_post(): void
- {
- $this->getTestingUser();
-
- $post = Post::factory()->create();
- $expectedData = $post->toArray();
-
- $this->getJson(route('api.posts.view', ['post' => $post->getKey()]))
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
- }
-
- public function test_view_post_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $post = Post::factory()->create();
-
- $this->getJson(route('api.posts.view', ['post' => $post->getKey()]))
- ->assertForbidden();
- }
-
- public function test_view_not_existing_post(): void
- {
- $this->getTestingUser();
-
- $this->getJson(route('api.posts.view', ['post' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__32.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__32.txt
deleted file mode 100644
index 00c9255..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__32.txt
+++ /dev/null
@@ -1,47 +0,0 @@
- 'view-post',
- 'roles' => '',
- ];
-
- public function test_list_posts(): void
- {
- $this->getTestingUser();
-
- Post::factory()->count(2)->create();
-
- $this->getJson(route('api.posts.list'))
- ->assertOk()
- ->assertJsonStructure([
- 'links',
- 'meta',
- 'data'
- ])
- ->assertJsonCount(Post::query()->count(), 'data');
- }
-
- public function test_list_posts_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- Post::factory()->count(2)->create();
-
- $this->getJson(route('api.posts.list'))
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__33.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__33.txt
deleted file mode 100644
index 4c6d30a..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__33.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-all());
- }
-
- public function asController(CreateCommentRequest $request): JsonResponse
- {
- $comment = $this->handle($request->toDTO());
-
- return (new CommentResource($comment))->created();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__34.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__34.txt
deleted file mode 100644
index 5fe31fe..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__34.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-all();
-
- if (empty($data)) {
- throw new UpdateResourceFailedException();
- }
-
- $comment->update($data);
-
- return $comment;
- }
-
- public function asController(UpdateCommentRequest $request, Comment $comment): CommentResource
- {
- $comment = $this->handle($comment, $request->toDTO());
-
- return new CommentResource($comment);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__35.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__35.txt
deleted file mode 100644
index 6facba3..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__35.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-delete();
- }
-
- public function asController(DeleteCommentRequest $request, Comment $comment): JsonResponse
- {
- $this->handle($comment);
-
- return $this->noContent();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__36.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__36.txt
deleted file mode 100644
index 878e02d..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__36.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-build();
- }
-
- public function asController(ViewCommentRequest $request, Comment $comment): CommentResource
- {
- return new CommentResource($this->handle($request, $comment));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__37.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__37.txt
deleted file mode 100644
index f4ec852..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__37.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-build()
- ->jsonPaginate();
- }
-
- public function asController(ListCommentsRequest $request): ResourceCollection
- {
- return CommentResource::collection($this->handle($request));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__38.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__38.txt
deleted file mode 100644
index ffdce7c..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__38.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-handle(new CreatePermissionDTO(
- name: 'view-comment',
- display_name: 'View any "comments"',
- group: 'comments'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'create-comment',
- display_name: 'Create "comments"',
- group: 'comments'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'update-comment',
- display_name: 'Update any "comments"',
- group: 'comments'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'delete-comment',
- display_name: 'Delete any "comments"',
- group: 'comments'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'force-delete-comment',
- display_name: 'Force delete any "comments"',
- group: 'comments'
- ));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__4.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__4.txt
deleted file mode 100644
index 91b133e..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__4.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-all();
-
- if (empty($data)) {
- throw new UpdateResourceFailedException();
- }
-
- $post->update($data);
-
- return $post;
- }
-
- public function asController(UpdatePostRequest $request, Post $post): PostResource
- {
- $post = $this->handle($post, $request->toDTO());
-
- return new PostResource($post);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__40.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__40.txt
deleted file mode 100644
index 4ffab35..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__40.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-can('view-comment');
- }
-
- /**
- * Determine whether the user can view the model.
- */
- public function view(User $user, Comment $comment): bool
- {
- return $user->can('view-comment');
- }
-
- /**
- * Determine whether the user can create models.
- */
- public function create(User $user): bool
- {
- return $user->can('create-comment');
- }
-
- /**
- * Determine whether the user can update the model.
- */
- public function update(User $user, Comment $comment): bool
- {
- return $user->can('update-comment');
- }
-
- /**
- * Determine whether the user can delete the model.
- */
- public function delete(User $user, Comment $comment): bool
- {
- return $user->can('delete-comment');
- }
-
- /**
- * Determine whether the user can restore the model.
- */
- public function restore(User $user, Comment $comment): bool
- {
- return $user->can('delete-comment');
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- */
- public function forceDelete(User $user, Comment $comment): bool
- {
- return $user->can('force-delete-comment');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__43.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__43.txt
deleted file mode 100644
index dca9938..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__43.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-registerMigrations();
- // $this->registerTranslations();
- // $this->registerCommands();
- // $this->registerViews();
- }
-
- /**
- * Get the services provided by the provider.
- */
- public function provides(): array
- {
- return [];
- }
-
- /**
- * Register translations.
- */
- public function registerTranslations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/lang');
- $langPath = resource_path('lang/modules/' . $this->moduleKey);
-
- $this->loadTranslationsFrom($sourcePath, $this->moduleKey);
-
- $this->publishes([
- $sourcePath => $langPath,
- ], 'translations');
- }
-
- /**
- * Register views.
- */
- public function registerViews(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/views');
- $viewsPath = resource_path('views/modules/' . $this->moduleKey);
-
- $this->loadViewsFrom(
- array_merge($this->getPublishableViewPaths($this->moduleKey), [$sourcePath]),
- $this->moduleKey
- );
-
- $this->publishes([
- $sourcePath => $viewsPath
- ], 'views');
- }
-
- /**
- * Register migrations.
- */
- public function registerMigrations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Data/Migrations');
- $migrationsPath = database_path('migrations');
-
- $this->loadMigrationsFrom($sourcePath);
-
- $this->publishes([
- $sourcePath => $migrationsPath
- ], 'migrations');
- }
-
- /**
- * Register artisan commands.
- */
- public function registerCommands(): void
- {
- if ($this->app->runningInConsole()) {
- $this->loadCommands(module_path($this->moduleName, 'UI/CLI/Commands'));
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__46.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__46.txt
deleted file mode 100644
index ccd452c..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__46.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__47.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__47.txt
deleted file mode 100644
index 86ac883..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__47.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__49.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__49.txt
deleted file mode 100644
index bfc4a94..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__49.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-route('comment');
- return $comment && Gate::check('update', $comment);
- }
-
- public function toDTO(): UpdateCommentDTO
- {
- return new UpdateCommentDTO($this->validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__5.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__5.txt
deleted file mode 100644
index 4cd3469..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__5.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-delete();
- }
-
- public function asController(DeletePostRequest $request, Post $post): JsonResponse
- {
- $this->handle($post);
-
- return $this->noContent();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__50.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__50.txt
deleted file mode 100644
index f6bc3e6..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__50.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('comment');
- return $comment && Gate::check('delete', $comment);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__51.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__51.txt
deleted file mode 100644
index 9a4ebd8..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__51.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('comment');
- return $comment && Gate::check('view', $comment);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__52.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__52.txt
deleted file mode 100644
index 973fe91..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__52.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-name('api.comments.create');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__54.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__54.txt
deleted file mode 100644
index 745efd1..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__54.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.comments.update');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__55.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__55.txt
deleted file mode 100644
index 84831ce..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__55.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.comments.delete');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__56.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__56.txt
deleted file mode 100644
index b330ee7..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__56.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.comments.view');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__57.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__57.txt
deleted file mode 100644
index d666711..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__57.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.comments.list');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__58.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__58.txt
deleted file mode 100644
index 2c51daf..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__58.txt
+++ /dev/null
@@ -1,58 +0,0 @@
- 'create-comment',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_create_comment(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.comments.create'), $data)
- ->assertCreated()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->has('id')
- ->whereAll($data)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(Comment::class, $data);
- }
-
- public function test_create_comment_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.comments.create'), $data)
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__59.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__59.txt
deleted file mode 100644
index 1de9a34..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__59.txt
+++ /dev/null
@@ -1,74 +0,0 @@
- 'update-comment',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_update_comment(): void
- {
- $this->getTestingUser();
-
- $comment = Comment::factory()->create();
-
- $data = $this->getTestData();
- $expectedData = array_merge($data, [
- 'id' => $comment->getKey(),
- ]);
-
- $this->patchJson(route('api.comments.update', ['comment' => $comment->getKey()]), $data)
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(Comment::class, $expectedData);
- }
-
- public function test_update_comment_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $comment = Comment::factory()->create();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.comments.update', ['comment' => $comment->getKey()]), $data)
- ->assertForbidden();
- }
-
- public function test_update_non_existing_comment(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.comments.update', ['comment' => 7777]), $data)
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__6.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__6.txt
deleted file mode 100644
index 5187ca6..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__6.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-build();
- }
-
- public function asController(ViewPostRequest $request, Post $post): PostResource
- {
- return new PostResource($this->handle($request, $post));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__60.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__60.txt
deleted file mode 100644
index 583638f..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__60.txt
+++ /dev/null
@@ -1,51 +0,0 @@
- 'delete-comment',
- 'roles' => '',
- ];
-
- public function test_delete_comment(): void
- {
- $this->getTestingUser();
-
- $comment = Comment::factory()->create();
-
- $this->deleteJson(route('api.comments.delete', ['comment' => $comment->getKey()]))
- ->assertNoContent();
-
- $this->assertNull(Comment::find($comment->getKey()));
- }
-
- public function test_delete_comment_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $comment = Comment::factory()->create();
-
- $this->deleteJson(route('api.comments.delete', ['comment' => $comment->getKey()]))
- ->assertForbidden();
- }
-
- public function test_delete_not_existing_comment(): void
- {
- $this->getTestingUser();
-
- $this->deleteJson(route('api.comments.delete', ['comment' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__61.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__61.txt
deleted file mode 100644
index bf55c65..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__61.txt
+++ /dev/null
@@ -1,57 +0,0 @@
- 'view-comment',
- 'roles' => '',
- ];
-
- public function test_view_comment(): void
- {
- $this->getTestingUser();
-
- $comment = Comment::factory()->create();
- $expectedData = $comment->toArray();
-
- $this->getJson(route('api.comments.view', ['comment' => $comment->getKey()]))
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
- }
-
- public function test_view_comment_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $comment = Comment::factory()->create();
-
- $this->getJson(route('api.comments.view', ['comment' => $comment->getKey()]))
- ->assertForbidden();
- }
-
- public function test_view_not_existing_comment(): void
- {
- $this->getTestingUser();
-
- $this->getJson(route('api.comments.view', ['comment' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__62.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__62.txt
deleted file mode 100644
index 776fd21..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__62.txt
+++ /dev/null
@@ -1,47 +0,0 @@
- 'view-comment',
- 'roles' => '',
- ];
-
- public function test_list_comments(): void
- {
- $this->getTestingUser();
-
- Comment::factory()->count(2)->create();
-
- $this->getJson(route('api.comments.list'))
- ->assertOk()
- ->assertJsonStructure([
- 'links',
- 'meta',
- 'data'
- ])
- ->assertJsonCount(Comment::query()->count(), 'data');
- }
-
- public function test_list_comments_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- Comment::factory()->count(2)->create();
-
- $this->getJson(route('api.comments.list'))
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__7.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__7.txt
deleted file mode 100644
index 464b945..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__7.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-build()
- ->jsonPaginate();
- }
-
- public function asController(ListPostsRequest $request): ResourceCollection
- {
- return PostResource::collection($this->handle($request));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__8.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__8.txt
deleted file mode 100644
index 4b8a96e..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__8.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-handle(new CreatePermissionDTO(
- name: 'view-post',
- display_name: 'View any "posts"',
- group: 'posts'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'create-post',
- display_name: 'Create "posts"',
- group: 'posts'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'update-post',
- display_name: 'Update any "posts"',
- group: 'posts'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'delete-post',
- display_name: 'Delete any "posts"',
- group: 'posts'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'force-delete-post',
- display_name: 'Force delete any "posts"',
- group: 'posts'
- ));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__1.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__1.txt
deleted file mode 100644
index f605374..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__1.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-all());
- }
-
- public function asController(CreateArticleRequest $request): JsonResponse
- {
- $article = $this->handle($request->toDTO());
-
- return (new ArticleResource($article))->created();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__10.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__10.txt
deleted file mode 100644
index cd3c04a..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__10.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-can('view-article');
- }
-
- /**
- * Determine whether the user can view the model.
- */
- public function view(User $user, Article $article): bool
- {
- return $user->can('view-article');
- }
-
- /**
- * Determine whether the user can create models.
- */
- public function create(User $user): bool
- {
- return $user->can('create-article');
- }
-
- /**
- * Determine whether the user can update the model.
- */
- public function update(User $user, Article $article): bool
- {
- return $user->can('update-article');
- }
-
- /**
- * Determine whether the user can delete the model.
- */
- public function delete(User $user, Article $article): bool
- {
- return $user->can('delete-article');
- }
-
- /**
- * Determine whether the user can restore the model.
- */
- public function restore(User $user, Article $article): bool
- {
- return $user->can('delete-article');
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- */
- public function forceDelete(User $user, Article $article): bool
- {
- return $user->can('force-delete-article');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__11.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__11.txt
deleted file mode 100644
index 9cb9660..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__11.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-registerMigrations();
- // $this->registerTranslations();
- // $this->registerCommands();
- // $this->registerViews();
- }
-
- /**
- * Get the services provided by the provider.
- */
- public function provides(): array
- {
- return [];
- }
-
- /**
- * Register translations.
- */
- public function registerTranslations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/lang');
- $langPath = resource_path('lang/modules/' . $this->moduleKey);
-
- $this->loadTranslationsFrom($sourcePath, $this->moduleKey);
-
- $this->publishes([
- $sourcePath => $langPath,
- ], 'translations');
- }
-
- /**
- * Register views.
- */
- public function registerViews(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/views');
- $viewsPath = resource_path('views/modules/' . $this->moduleKey);
-
- $this->loadViewsFrom(
- array_merge($this->getPublishableViewPaths($this->moduleKey), [$sourcePath]),
- $this->moduleKey
- );
-
- $this->publishes([
- $sourcePath => $viewsPath
- ], 'views');
- }
-
- /**
- * Register migrations.
- */
- public function registerMigrations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Data/Migrations');
- $migrationsPath = database_path('migrations');
-
- $this->loadMigrationsFrom($sourcePath);
-
- $this->publishes([
- $sourcePath => $migrationsPath
- ], 'migrations');
- }
-
- /**
- * Register artisan commands.
- */
- public function registerCommands(): void
- {
- if ($this->app->runningInConsole()) {
- $this->loadCommands(module_path($this->moduleName, 'UI/CLI/Commands'));
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__15.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__15.txt
deleted file mode 100644
index 0dcdf06..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__15.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__17.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__17.txt
deleted file mode 100644
index c4cc41c..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__17.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-route('article');
- return $article && Gate::check('update', $article);
- }
-
- public function toDTO(): UpdateArticleDTO
- {
- return new UpdateArticleDTO($this->validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__18.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__18.txt
deleted file mode 100644
index 8d99840..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__18.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('article');
- return $article && Gate::check('delete', $article);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__19.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__19.txt
deleted file mode 100644
index 358aa05..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__19.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('article');
- return $article && Gate::check('view', $article);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__2.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__2.txt
deleted file mode 100644
index 6dd1d52..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__2.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-all();
-
- if (empty($data)) {
- throw new UpdateResourceFailedException();
- }
-
- $article->update($data);
-
- return $article;
- }
-
- public function asController(UpdateArticleRequest $request, Article $article): ArticleResource
- {
- $article = $this->handle($article, $request->toDTO());
-
- return new ArticleResource($article);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__20.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__20.txt
deleted file mode 100644
index d663831..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__20.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-name('api.articles.create');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__22.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__22.txt
deleted file mode 100644
index 7e76fc3..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__22.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.update');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__23.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__23.txt
deleted file mode 100644
index cceba8f..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__23.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.delete');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__24.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__24.txt
deleted file mode 100644
index 98fedcf..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__24.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.view');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__25.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__25.txt
deleted file mode 100644
index 093f946..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__25.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.list');
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__26.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__26.txt
deleted file mode 100644
index 02c4e58..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__26.txt
+++ /dev/null
@@ -1,58 +0,0 @@
- 'create-article',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_create_article(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.articles.create'), $data)
- ->assertCreated()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->has('id')
- ->whereAll($data)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(Article::class, $data);
- }
-
- public function test_create_article_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.articles.create'), $data)
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__27.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__27.txt
deleted file mode 100644
index 2ae1db3..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__27.txt
+++ /dev/null
@@ -1,74 +0,0 @@
- 'update-article',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_update_article(): void
- {
- $this->getTestingUser();
-
- $article = Article::factory()->create();
-
- $data = $this->getTestData();
- $expectedData = array_merge($data, [
- 'id' => $article->getKey(),
- ]);
-
- $this->patchJson(route('api.articles.update', ['article' => $article->getKey()]), $data)
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(Article::class, $expectedData);
- }
-
- public function test_update_article_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $article = Article::factory()->create();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.articles.update', ['article' => $article->getKey()]), $data)
- ->assertForbidden();
- }
-
- public function test_update_non_existing_article(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.articles.update', ['article' => 7777]), $data)
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__28.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__28.txt
deleted file mode 100644
index 76e7943..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__28.txt
+++ /dev/null
@@ -1,51 +0,0 @@
- 'delete-article',
- 'roles' => '',
- ];
-
- public function test_delete_article(): void
- {
- $this->getTestingUser();
-
- $article = Article::factory()->create();
-
- $this->deleteJson(route('api.articles.delete', ['article' => $article->getKey()]))
- ->assertNoContent();
-
- $this->assertNull(Article::find($article->getKey()));
- }
-
- public function test_delete_article_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $article = Article::factory()->create();
-
- $this->deleteJson(route('api.articles.delete', ['article' => $article->getKey()]))
- ->assertForbidden();
- }
-
- public function test_delete_not_existing_article(): void
- {
- $this->getTestingUser();
-
- $this->deleteJson(route('api.articles.delete', ['article' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__29.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__29.txt
deleted file mode 100644
index 5450de3..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__29.txt
+++ /dev/null
@@ -1,57 +0,0 @@
- 'view-article',
- 'roles' => '',
- ];
-
- public function test_view_article(): void
- {
- $this->getTestingUser();
-
- $article = Article::factory()->create();
- $expectedData = $article->toArray();
-
- $this->getJson(route('api.articles.view', ['article' => $article->getKey()]))
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
- }
-
- public function test_view_article_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $article = Article::factory()->create();
-
- $this->getJson(route('api.articles.view', ['article' => $article->getKey()]))
- ->assertForbidden();
- }
-
- public function test_view_not_existing_article(): void
- {
- $this->getTestingUser();
-
- $this->getJson(route('api.articles.view', ['article' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__3.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__3.txt
deleted file mode 100644
index ddf1544..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__3.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-delete();
- }
-
- public function asController(DeleteArticleRequest $request, Article $article): JsonResponse
- {
- $this->handle($article);
-
- return $this->noContent();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__30.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__30.txt
deleted file mode 100644
index adfb1ec..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__30.txt
+++ /dev/null
@@ -1,47 +0,0 @@
- 'view-article',
- 'roles' => '',
- ];
-
- public function test_list_articles(): void
- {
- $this->getTestingUser();
-
- Article::factory()->count(2)->create();
-
- $this->getJson(route('api.articles.list'))
- ->assertOk()
- ->assertJsonStructure([
- 'links',
- 'meta',
- 'data'
- ])
- ->assertJsonCount(Article::query()->count(), 'data');
- }
-
- public function test_list_articles_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- Article::factory()->count(2)->create();
-
- $this->getJson(route('api.articles.list'))
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__4.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__4.txt
deleted file mode 100644
index 9d2ab5c..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__4.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-build();
- }
-
- public function asController(ViewArticleRequest $request, Article $article): ArticleResource
- {
- return new ArticleResource($this->handle($request, $article));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__5.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__5.txt
deleted file mode 100644
index 734c60d..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__5.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-build()
- ->jsonPaginate();
- }
-
- public function asController(ListArticlesRequest $request): ResourceCollection
- {
- return ArticleResource::collection($this->handle($request));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__6.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__6.txt
deleted file mode 100644
index 5f63c9d..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__6.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-handle(new CreatePermissionDTO(
- name: 'view-article',
- display_name: 'View any "articles"',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'create-article',
- display_name: 'Create "articles"',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'update-article',
- display_name: 'Update any "articles"',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'delete-article',
- display_name: 'Delete any "articles"',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'force-delete-article',
- display_name: 'Force delete any "articles"',
- group: 'articles'
- ));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__8.txt b/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__8.txt
deleted file mode 100644
index 9065ecf..0000000
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__8.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-view('view.name');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/MailMakeCommandTest__it_can_change_the_default_path_for_plain_mail_file__1.txt b/tests/Commands/Generators/__snapshots__/MailMakeCommandTest__it_can_change_the_default_path_for_plain_mail_file__1.txt
deleted file mode 100644
index 25ba89c..0000000
--- a/tests/Commands/Generators/__snapshots__/MailMakeCommandTest__it_can_change_the_default_path_for_plain_mail_file__1.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-view('view.name');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/MailMakeCommandTest__it_generated_correct_plain_mail_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/MailMakeCommandTest__it_generated_correct_plain_mail_file_with_content__1.txt
deleted file mode 100644
index 666a1d3..0000000
--- a/tests/Commands/Generators/__snapshots__/MailMakeCommandTest__it_generated_correct_plain_mail_file_with_content__1.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-view('view.name');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/MailMakeCommandTest__it_generated_correct_queued_mail_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/MailMakeCommandTest__it_generated_correct_queued_mail_file_with_content__1.txt
deleted file mode 100644
index 5f01c07..0000000
--- a/tests/Commands/Generators/__snapshots__/MailMakeCommandTest__it_generated_correct_queued_mail_file_with_content__1.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-view('view.name');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/MiddlewareMakeCommandTest__it_can_change_the_default_namespace_for_middleware_file__1.txt b/tests/Commands/Generators/__snapshots__/MiddlewareMakeCommandTest__it_can_change_the_default_namespace_for_middleware_file__1.txt
deleted file mode 100644
index 8983d22..0000000
--- a/tests/Commands/Generators/__snapshots__/MiddlewareMakeCommandTest__it_can_change_the_default_namespace_for_middleware_file__1.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-unsignedBigInteger('user_id')->index();
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- $table->unsignedBigInteger('role_id')->index();
- $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
- $table->primary(['user_id', 'role_id']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('user_role');
- }
-};
diff --git a/tests/Commands/Generators/__snapshots__/ModelMakeCommandTest__it_can_change_the_default_namespace_for_plain_model_file__1.txt b/tests/Commands/Generators/__snapshots__/ModelMakeCommandTest__it_can_change_the_default_namespace_for_plain_model_file__1.txt
deleted file mode 100644
index 6511aef..0000000
--- a/tests/Commands/Generators/__snapshots__/ModelMakeCommandTest__it_can_change_the_default_namespace_for_plain_model_file__1.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-can('view-post-comment');
- }
-
- /**
- * Determine whether the user can view the model.
- */
- public function view(User $user, PostComment $postComment): bool
- {
- return $user->can('view-post-comment');
- }
-
- /**
- * Determine whether the user can create models.
- */
- public function create(User $user): bool
- {
- return $user->can('create-post-comment');
- }
-
- /**
- * Determine whether the user can update the model.
- */
- public function update(User $user, PostComment $postComment): bool
- {
- return $user->can('update-post-comment');
- }
-
- /**
- * Determine whether the user can delete the model.
- */
- public function delete(User $user, PostComment $postComment): bool
- {
- return $user->can('delete-post-comment');
- }
-
- /**
- * Determine whether the user can restore the model.
- */
- public function restore(User $user, PostComment $postComment): bool
- {
- return $user->can('delete-post-comment');
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- */
- public function forceDelete(User $user, PostComment $postComment): bool
- {
- return $user->can('force-delete-post-comment');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__13.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__13.txt
deleted file mode 100644
index dca9938..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__13.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-registerMigrations();
- // $this->registerTranslations();
- // $this->registerCommands();
- // $this->registerViews();
- }
-
- /**
- * Get the services provided by the provider.
- */
- public function provides(): array
- {
- return [];
- }
-
- /**
- * Register translations.
- */
- public function registerTranslations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/lang');
- $langPath = resource_path('lang/modules/' . $this->moduleKey);
-
- $this->loadTranslationsFrom($sourcePath, $this->moduleKey);
-
- $this->publishes([
- $sourcePath => $langPath,
- ], 'translations');
- }
-
- /**
- * Register views.
- */
- public function registerViews(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/views');
- $viewsPath = resource_path('views/modules/' . $this->moduleKey);
-
- $this->loadViewsFrom(
- array_merge($this->getPublishableViewPaths($this->moduleKey), [$sourcePath]),
- $this->moduleKey
- );
-
- $this->publishes([
- $sourcePath => $viewsPath
- ], 'views');
- }
-
- /**
- * Register migrations.
- */
- public function registerMigrations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Data/Migrations');
- $migrationsPath = database_path('migrations');
-
- $this->loadMigrationsFrom($sourcePath);
-
- $this->publishes([
- $sourcePath => $migrationsPath
- ], 'migrations');
- }
-
- /**
- * Register artisan commands.
- */
- public function registerCommands(): void
- {
- if ($this->app->runningInConsole()) {
- $this->loadCommands(module_path($this->moduleName, 'UI/CLI/Commands'));
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__15.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__15.txt
deleted file mode 100644
index 9052338..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__15.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__17.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__17.txt
deleted file mode 100644
index 52d0931..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__17.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__19.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__19.txt
deleted file mode 100644
index 34b2104..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__19.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-route('postComment');
- return $postComment && Gate::check('update', $postComment);
- }
-
- public function toDTO(): UpdatePostCommentDTO
- {
- return new UpdatePostCommentDTO($this->validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__2.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__2.txt
deleted file mode 100644
index e2e845d..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__2.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "example/blog",
- "description": "",
- "authors": [
- {
- "name": "Example name",
- "email": "example@example.com"
- }
- ],
- "autoload": {
- "psr-4": {
- "App\\Modules\\Blog\\": ""
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__20.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__20.txt
deleted file mode 100644
index d55c8eb..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__20.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('postComment');
- return $postComment && Gate::check('delete', $postComment);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__21.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__21.txt
deleted file mode 100644
index 574b56e..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__21.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('postComment');
- return $postComment && Gate::check('view', $postComment);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__22.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__22.txt
deleted file mode 100644
index a338831..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__22.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-name('api.post_comments.create');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__24.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__24.txt
deleted file mode 100644
index 5c8081a..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__24.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.post_comments.update');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__25.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__25.txt
deleted file mode 100644
index 601e578..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__25.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.post_comments.delete');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__26.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__26.txt
deleted file mode 100644
index 4bd5709..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__26.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.post_comments.view');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__27.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__27.txt
deleted file mode 100644
index 8711b3a..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__27.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.post_comments.list');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__28.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__28.txt
deleted file mode 100644
index 250f1a1..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__28.txt
+++ /dev/null
@@ -1,58 +0,0 @@
- 'create-post-comment',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_create_post_comment(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.post_comments.create'), $data)
- ->assertCreated()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->has('id')
- ->whereAll($data)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(PostComment::class, $data);
- }
-
- public function test_create_post_comment_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.post_comments.create'), $data)
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__29.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__29.txt
deleted file mode 100644
index 196bb05..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__29.txt
+++ /dev/null
@@ -1,74 +0,0 @@
- 'update-post-comment',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_update_post_comment(): void
- {
- $this->getTestingUser();
-
- $postComment = PostComment::factory()->create();
-
- $data = $this->getTestData();
- $expectedData = array_merge($data, [
- 'id' => $postComment->getKey(),
- ]);
-
- $this->patchJson(route('api.post_comments.update', ['postComment' => $postComment->getKey()]), $data)
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(PostComment::class, $expectedData);
- }
-
- public function test_update_post_comment_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $postComment = PostComment::factory()->create();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.post_comments.update', ['postComment' => $postComment->getKey()]), $data)
- ->assertForbidden();
- }
-
- public function test_update_non_existing_post_comment(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.post_comments.update', ['postComment' => 7777]), $data)
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__3.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__3.txt
deleted file mode 100644
index 91c877f..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__3.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-all());
- }
-
- public function asController(CreatePostCommentRequest $request): JsonResponse
- {
- $postComment = $this->handle($request->toDTO());
-
- return (new PostCommentResource($postComment))->created();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__30.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__30.txt
deleted file mode 100644
index 7d73214..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__30.txt
+++ /dev/null
@@ -1,51 +0,0 @@
- 'delete-post-comment',
- 'roles' => '',
- ];
-
- public function test_delete_post_comment(): void
- {
- $this->getTestingUser();
-
- $postComment = PostComment::factory()->create();
-
- $this->deleteJson(route('api.post_comments.delete', ['postComment' => $postComment->getKey()]))
- ->assertNoContent();
-
- $this->assertNull(PostComment::find($postComment->getKey()));
- }
-
- public function test_delete_post_comment_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $postComment = PostComment::factory()->create();
-
- $this->deleteJson(route('api.post_comments.delete', ['postComment' => $postComment->getKey()]))
- ->assertForbidden();
- }
-
- public function test_delete_not_existing_post_comment(): void
- {
- $this->getTestingUser();
-
- $this->deleteJson(route('api.post_comments.delete', ['postComment' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__31.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__31.txt
deleted file mode 100644
index 123294e..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__31.txt
+++ /dev/null
@@ -1,57 +0,0 @@
- 'view-post-comment',
- 'roles' => '',
- ];
-
- public function test_view_post_comment(): void
- {
- $this->getTestingUser();
-
- $postComment = PostComment::factory()->create();
- $expectedData = $postComment->toArray();
-
- $this->getJson(route('api.post_comments.view', ['postComment' => $postComment->getKey()]))
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
- }
-
- public function test_view_post_comment_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $postComment = PostComment::factory()->create();
-
- $this->getJson(route('api.post_comments.view', ['postComment' => $postComment->getKey()]))
- ->assertForbidden();
- }
-
- public function test_view_not_existing_post_comment(): void
- {
- $this->getTestingUser();
-
- $this->getJson(route('api.post_comments.view', ['postComment' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__32.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__32.txt
deleted file mode 100644
index 1a4ed7d..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__32.txt
+++ /dev/null
@@ -1,47 +0,0 @@
- 'view-post-comment',
- 'roles' => '',
- ];
-
- public function test_list_post_comments(): void
- {
- $this->getTestingUser();
-
- PostComment::factory()->count(2)->create();
-
- $this->getJson(route('api.post_comments.list'))
- ->assertOk()
- ->assertJsonStructure([
- 'links',
- 'meta',
- 'data'
- ])
- ->assertJsonCount(PostComment::query()->count(), 'data');
- }
-
- public function test_list_post_comments_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- PostComment::factory()->count(2)->create();
-
- $this->getJson(route('api.post_comments.list'))
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__33.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__33.txt
deleted file mode 100644
index 48bf96f..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__33.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-id();
-
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('post_comments');
- }
-};
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__34.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__34.txt
deleted file mode 100644
index 48bf96f..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__34.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-id();
-
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('post_comments');
- }
-};
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__4.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__4.txt
deleted file mode 100644
index 4cafb66..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__4.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-all();
-
- if (empty($data)) {
- throw new UpdateResourceFailedException();
- }
-
- $postComment->update($data);
-
- return $postComment;
- }
-
- public function asController(UpdatePostCommentRequest $request, PostComment $postComment): PostCommentResource
- {
- $postComment = $this->handle($postComment, $request->toDTO());
-
- return new PostCommentResource($postComment);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__5.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__5.txt
deleted file mode 100644
index ba3ac3c..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__5.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-delete();
- }
-
- public function asController(DeletePostCommentRequest $request, PostComment $postComment): JsonResponse
- {
- $this->handle($postComment);
-
- return $this->noContent();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__6.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__6.txt
deleted file mode 100644
index c34f6c8..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__6.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-build();
- }
-
- public function asController(ViewPostCommentRequest $request, PostComment $postComment): PostCommentResource
- {
- return new PostCommentResource($this->handle($request, $postComment));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__7.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__7.txt
deleted file mode 100644
index 9e3d50e..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__7.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-build()
- ->jsonPaginate();
- }
-
- public function asController(ListPostCommentsRequest $request): ResourceCollection
- {
- return PostCommentResource::collection($this->handle($request));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__8.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__8.txt
deleted file mode 100644
index a2f9127..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__8.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-handle(new CreatePermissionDTO(
- name: 'view-post-comment',
- display_name: 'View any "post-comments"',
- group: 'post-comments'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'create-post-comment',
- display_name: 'Create "post-comments"',
- group: 'post-comments'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'update-post-comment',
- display_name: 'Update any "post-comments"',
- group: 'post-comments'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'delete-post-comment',
- display_name: 'Delete any "post-comments"',
- group: 'post-comments'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'force-delete-post-comment',
- display_name: 'Force delete any "post-comments"',
- group: 'post-comments'
- ));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__1.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__1.txt
deleted file mode 100644
index f605374..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__1.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-all());
- }
-
- public function asController(CreateArticleRequest $request): JsonResponse
- {
- $article = $this->handle($request->toDTO());
-
- return (new ArticleResource($article))->created();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__10.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__10.txt
deleted file mode 100644
index cd3c04a..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__10.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-can('view-article');
- }
-
- /**
- * Determine whether the user can view the model.
- */
- public function view(User $user, Article $article): bool
- {
- return $user->can('view-article');
- }
-
- /**
- * Determine whether the user can create models.
- */
- public function create(User $user): bool
- {
- return $user->can('create-article');
- }
-
- /**
- * Determine whether the user can update the model.
- */
- public function update(User $user, Article $article): bool
- {
- return $user->can('update-article');
- }
-
- /**
- * Determine whether the user can delete the model.
- */
- public function delete(User $user, Article $article): bool
- {
- return $user->can('delete-article');
- }
-
- /**
- * Determine whether the user can restore the model.
- */
- public function restore(User $user, Article $article): bool
- {
- return $user->can('delete-article');
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- */
- public function forceDelete(User $user, Article $article): bool
- {
- return $user->can('force-delete-article');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__11.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__11.txt
deleted file mode 100644
index 9cb9660..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__11.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-registerMigrations();
- // $this->registerTranslations();
- // $this->registerCommands();
- // $this->registerViews();
- }
-
- /**
- * Get the services provided by the provider.
- */
- public function provides(): array
- {
- return [];
- }
-
- /**
- * Register translations.
- */
- public function registerTranslations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/lang');
- $langPath = resource_path('lang/modules/' . $this->moduleKey);
-
- $this->loadTranslationsFrom($sourcePath, $this->moduleKey);
-
- $this->publishes([
- $sourcePath => $langPath,
- ], 'translations');
- }
-
- /**
- * Register views.
- */
- public function registerViews(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/views');
- $viewsPath = resource_path('views/modules/' . $this->moduleKey);
-
- $this->loadViewsFrom(
- array_merge($this->getPublishableViewPaths($this->moduleKey), [$sourcePath]),
- $this->moduleKey
- );
-
- $this->publishes([
- $sourcePath => $viewsPath
- ], 'views');
- }
-
- /**
- * Register migrations.
- */
- public function registerMigrations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Data/Migrations');
- $migrationsPath = database_path('migrations');
-
- $this->loadMigrationsFrom($sourcePath);
-
- $this->publishes([
- $sourcePath => $migrationsPath
- ], 'migrations');
- }
-
- /**
- * Register artisan commands.
- */
- public function registerCommands(): void
- {
- if ($this->app->runningInConsole()) {
- $this->loadCommands(module_path($this->moduleName, 'UI/CLI/Commands'));
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__13.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__13.txt
deleted file mode 100644
index a2fccb5..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__13.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__14.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__14.txt
deleted file mode 100644
index b3b0b6d..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__14.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__15.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__15.txt
deleted file mode 100644
index 0dcdf06..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__15.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__17.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__17.txt
deleted file mode 100644
index c4cc41c..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__17.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-route('article');
- return $article && Gate::check('update', $article);
- }
-
- public function toDTO(): UpdateArticleDTO
- {
- return new UpdateArticleDTO($this->validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__18.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__18.txt
deleted file mode 100644
index 8d99840..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__18.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('article');
- return $article && Gate::check('delete', $article);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__19.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__19.txt
deleted file mode 100644
index 358aa05..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__19.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('article');
- return $article && Gate::check('view', $article);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__2.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__2.txt
deleted file mode 100644
index 6dd1d52..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__2.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-all();
-
- if (empty($data)) {
- throw new UpdateResourceFailedException();
- }
-
- $article->update($data);
-
- return $article;
- }
-
- public function asController(UpdateArticleRequest $request, Article $article): ArticleResource
- {
- $article = $this->handle($article, $request->toDTO());
-
- return new ArticleResource($article);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__20.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__20.txt
deleted file mode 100644
index d663831..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__20.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-name('api.articles.create');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__22.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__22.txt
deleted file mode 100644
index 7e76fc3..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__22.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.update');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__23.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__23.txt
deleted file mode 100644
index cceba8f..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__23.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.delete');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__24.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__24.txt
deleted file mode 100644
index 98fedcf..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__24.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.view');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__25.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__25.txt
deleted file mode 100644
index 093f946..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__25.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.list');
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__26.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__26.txt
deleted file mode 100644
index 02c4e58..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__26.txt
+++ /dev/null
@@ -1,58 +0,0 @@
- 'create-article',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_create_article(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.articles.create'), $data)
- ->assertCreated()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->has('id')
- ->whereAll($data)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(Article::class, $data);
- }
-
- public function test_create_article_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $data = $this->getTestData();
-
- $this->postJson(route('api.articles.create'), $data)
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__27.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__27.txt
deleted file mode 100644
index 2ae1db3..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__27.txt
+++ /dev/null
@@ -1,74 +0,0 @@
- 'update-article',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_update_article(): void
- {
- $this->getTestingUser();
-
- $article = Article::factory()->create();
-
- $data = $this->getTestData();
- $expectedData = array_merge($data, [
- 'id' => $article->getKey(),
- ]);
-
- $this->patchJson(route('api.articles.update', ['article' => $article->getKey()]), $data)
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(Article::class, $expectedData);
- }
-
- public function test_update_article_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $article = Article::factory()->create();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.articles.update', ['article' => $article->getKey()]), $data)
- ->assertForbidden();
- }
-
- public function test_update_non_existing_article(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('api.articles.update', ['article' => 7777]), $data)
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__28.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__28.txt
deleted file mode 100644
index 76e7943..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__28.txt
+++ /dev/null
@@ -1,51 +0,0 @@
- 'delete-article',
- 'roles' => '',
- ];
-
- public function test_delete_article(): void
- {
- $this->getTestingUser();
-
- $article = Article::factory()->create();
-
- $this->deleteJson(route('api.articles.delete', ['article' => $article->getKey()]))
- ->assertNoContent();
-
- $this->assertNull(Article::find($article->getKey()));
- }
-
- public function test_delete_article_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $article = Article::factory()->create();
-
- $this->deleteJson(route('api.articles.delete', ['article' => $article->getKey()]))
- ->assertForbidden();
- }
-
- public function test_delete_not_existing_article(): void
- {
- $this->getTestingUser();
-
- $this->deleteJson(route('api.articles.delete', ['article' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__29.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__29.txt
deleted file mode 100644
index 5450de3..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__29.txt
+++ /dev/null
@@ -1,57 +0,0 @@
- 'view-article',
- 'roles' => '',
- ];
-
- public function test_view_article(): void
- {
- $this->getTestingUser();
-
- $article = Article::factory()->create();
- $expectedData = $article->toArray();
-
- $this->getJson(route('api.articles.view', ['article' => $article->getKey()]))
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
- }
-
- public function test_view_article_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $article = Article::factory()->create();
-
- $this->getJson(route('api.articles.view', ['article' => $article->getKey()]))
- ->assertForbidden();
- }
-
- public function test_view_not_existing_article(): void
- {
- $this->getTestingUser();
-
- $this->getJson(route('api.articles.view', ['article' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__3.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__3.txt
deleted file mode 100644
index ddf1544..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__3.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-delete();
- }
-
- public function asController(DeleteArticleRequest $request, Article $article): JsonResponse
- {
- $this->handle($article);
-
- return $this->noContent();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__30.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__30.txt
deleted file mode 100644
index adfb1ec..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__30.txt
+++ /dev/null
@@ -1,47 +0,0 @@
- 'view-article',
- 'roles' => '',
- ];
-
- public function test_list_articles(): void
- {
- $this->getTestingUser();
-
- Article::factory()->count(2)->create();
-
- $this->getJson(route('api.articles.list'))
- ->assertOk()
- ->assertJsonStructure([
- 'links',
- 'meta',
- 'data'
- ])
- ->assertJsonCount(Article::query()->count(), 'data');
- }
-
- public function test_list_articles_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- Article::factory()->count(2)->create();
-
- $this->getJson(route('api.articles.list'))
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__4.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__4.txt
deleted file mode 100644
index 9d2ab5c..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__4.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-build();
- }
-
- public function asController(ViewArticleRequest $request, Article $article): ArticleResource
- {
- return new ArticleResource($this->handle($request, $article));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__5.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__5.txt
deleted file mode 100644
index 734c60d..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__5.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-build()
- ->jsonPaginate();
- }
-
- public function asController(ListArticlesRequest $request): ResourceCollection
- {
- return ArticleResource::collection($this->handle($request));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__6.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__6.txt
deleted file mode 100644
index 5f63c9d..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__6.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-handle(new CreatePermissionDTO(
- name: 'view-article',
- display_name: 'View any "articles"',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'create-article',
- display_name: 'Create "articles"',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'update-article',
- display_name: 'Update any "articles"',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'delete-article',
- display_name: 'Delete any "articles"',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'force-delete-article',
- display_name: 'Force delete any "articles"',
- group: 'articles'
- ));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__8.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__8.txt
deleted file mode 100644
index 9065ecf..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__8.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-registerMigrations();
- // $this->registerTranslations();
- // $this->registerCommands();
- // $this->registerViews();
- }
-
- /**
- * Get the services provided by the provider.
- */
- public function provides(): array
- {
- return [];
- }
-
- /**
- * Register translations.
- */
- public function registerTranslations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/lang');
- $langPath = resource_path('lang/modules/' . $this->moduleKey);
-
- $this->loadTranslationsFrom($sourcePath, $this->moduleKey);
-
- $this->publishes([
- $sourcePath => $langPath,
- ], 'translations');
- }
-
- /**
- * Register views.
- */
- public function registerViews(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/views');
- $viewsPath = resource_path('views/modules/' . $this->moduleKey);
-
- $this->loadViewsFrom(
- array_merge($this->getPublishableViewPaths($this->moduleKey), [$sourcePath]),
- $this->moduleKey
- );
-
- $this->publishes([
- $sourcePath => $viewsPath
- ], 'views');
- }
-
- /**
- * Register migrations.
- */
- public function registerMigrations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Data/Migrations');
- $migrationsPath = database_path('migrations');
-
- $this->loadMigrationsFrom($sourcePath);
-
- $this->publishes([
- $sourcePath => $migrationsPath
- ], 'migrations');
- }
-
- /**
- * Register artisan commands.
- */
- public function registerCommands(): void
- {
- if ($this->app->runningInConsole()) {
- $this->loadCommands(module_path($this->moduleName, 'UI/CLI/Commands'));
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_scaffold_files__1.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_scaffold_files__1.txt
deleted file mode 100644
index 3441218..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_scaffold_files__1.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "Article",
- "namespace": "App\\Modules\\Article",
- "alias": "article",
- "description": "Article module",
- "keywords": [],
- "priority": 0,
- "providers": [
- "App\\Modules\\Article\\Providers\\ArticleServiceProvider",
- "App\\Modules\\Article\\Providers\\RouteServiceProvider"
- ],
- "aliases": [],
- "files": [],
- "requires": []
-}
\ No newline at end of file
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_scaffold_files__2.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_scaffold_files__2.txt
deleted file mode 100644
index 02911b7..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_scaffold_files__2.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "example/article",
- "description": "",
- "authors": [
- {
- "name": "Example name",
- "email": "example@example.com"
- }
- ],
- "autoload": {
- "psr-4": {
- "App\\Modules\\Article\\": ""
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_scaffold_files__3.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_scaffold_files__3.txt
deleted file mode 100644
index fd8e4c1..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_scaffold_files__3.txt
+++ /dev/null
@@ -1,13 +0,0 @@
- 'Article',
-
-];
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generes_module_with_new_provider_location__1.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generes_module_with_new_provider_location__1.txt
deleted file mode 100644
index 52be439..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generes_module_with_new_provider_location__1.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "Article",
- "namespace": "App\\Modules\\Article",
- "alias": "article",
- "description": "Article module",
- "keywords": [],
- "priority": 0,
- "providers": [
- "App\\Modules\\Article\\Base\\Providers\\ArticleServiceProvider",
- "App\\Modules\\Article\\Base\\Providers\\RouteServiceProvider"
- ],
- "aliases": [],
- "files": [],
- "requires": []
-}
\ No newline at end of file
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generes_module_with_new_provider_location__2.txt b/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generes_module_with_new_provider_location__2.txt
deleted file mode 100644
index 02911b7..0000000
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generes_module_with_new_provider_location__2.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "example/article",
- "description": "",
- "authors": [
- {
- "name": "Example name",
- "email": "example@example.com"
- }
- ],
- "autoload": {
- "psr-4": {
- "App\\Modules\\Article\\": ""
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/NotificationMakeCommandTest__it_can_change_the_default_namespace_for_plain_notification_file__1.txt b/tests/Commands/Generators/__snapshots__/NotificationMakeCommandTest__it_can_change_the_default_namespace_for_plain_notification_file__1.txt
deleted file mode 100644
index 94859b1..0000000
--- a/tests/Commands/Generators/__snapshots__/NotificationMakeCommandTest__it_can_change_the_default_namespace_for_plain_notification_file__1.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-can('view-my-awesome-model');
- }
-
- /**
- * Determine whether the user can view the model.
- */
- public function view(User $user, MyAwesomeModel $myAwesomeModel): bool
- {
- return $user->can('view-my-awesome-model');
- }
-
- /**
- * Determine whether the user can create models.
- */
- public function create(User $user): bool
- {
- return $user->can('create-my-awesome-model');
- }
-
- /**
- * Determine whether the user can update the model.
- */
- public function update(User $user, MyAwesomeModel $myAwesomeModel): bool
- {
- return $user->can('update-my-awesome-model');
- }
-
- /**
- * Determine whether the user can delete the model.
- */
- public function delete(User $user, MyAwesomeModel $myAwesomeModel): bool
- {
- return $user->can('delete-my-awesome-model');
- }
-
- /**
- * Determine whether the user can restore the model.
- */
- public function restore(User $user, MyAwesomeModel $myAwesomeModel): bool
- {
- return $user->can('delete-my-awesome-model');
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- */
- public function forceDelete(User $user, MyAwesomeModel $myAwesomeModel): bool
- {
- return $user->can('force-delete-my-awesome-model');
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/PolicyMakeCommandTest__it_generated_correct_plain_policy_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/PolicyMakeCommandTest__it_generated_correct_plain_policy_file_with_content__1.txt
deleted file mode 100644
index f9db87f..0000000
--- a/tests/Commands/Generators/__snapshots__/PolicyMakeCommandTest__it_generated_correct_plain_policy_file_with_content__1.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-registerMigrations();
- // $this->registerTranslations();
- // $this->registerCommands();
- // $this->registerViews();
- }
-
- /**
- * Get the services provided by the provider.
- */
- public function provides(): array
- {
- return [];
- }
-
- /**
- * Register translations.
- */
- public function registerTranslations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/lang');
- $langPath = resource_path('lang/modules/' . $this->moduleKey);
-
- $this->loadTranslationsFrom($sourcePath, $this->moduleKey);
-
- $this->publishes([
- $sourcePath => $langPath,
- ], 'translations');
- }
-
- /**
- * Register views.
- */
- public function registerViews(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/views');
- $viewsPath = resource_path('views/modules/' . $this->moduleKey);
-
- $this->loadViewsFrom(
- array_merge($this->getPublishableViewPaths($this->moduleKey), [$sourcePath]),
- $this->moduleKey
- );
-
- $this->publishes([
- $sourcePath => $viewsPath
- ], 'views');
- }
-
- /**
- * Register migrations.
- */
- public function registerMigrations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Data/Migrations');
- $migrationsPath = database_path('migrations');
-
- $this->loadMigrationsFrom($sourcePath);
-
- $this->publishes([
- $sourcePath => $migrationsPath
- ], 'migrations');
- }
-
- /**
- * Register artisan commands.
- */
- public function registerCommands(): void
- {
- if ($this->app->runningInConsole()) {
- $this->loadCommands(module_path($this->moduleName, 'UI/CLI/Commands'));
- }
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ProviderMakeCommandTest__it_can_generate_route_provider_file__1.txt b/tests/Commands/Generators/__snapshots__/ProviderMakeCommandTest__it_can_generate_route_provider_file__1.txt
deleted file mode 100644
index d05bc76..0000000
--- a/tests/Commands/Generators/__snapshots__/ProviderMakeCommandTest__it_can_generate_route_provider_file__1.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-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('App\\Modules\\Article\\UI\\WEB\\Controllers')
- ->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/WEB/Routes'));
- });
- }
-
- /**
- * Define the "api" routes for the application.
- * These routes are typically stateless.
- */
- protected function mapApiRoutes(): void
- {
- Route::prefix('api')
- ->middleware('api')
-// ->namespace('App\\Modules\\Article\\UI\\API\\Controllers')
- ->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/API/Routes'));
- });
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_can_change_the_default_namespace_for_query_wizard_file__1.txt b/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_can_change_the_default_namespace_for_query_wizard_file__1.txt
deleted file mode 100644
index 5e3e6d7..0000000
--- a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_can_change_the_default_namespace_for_query_wizard_file__1.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_can_change_the_default_path_for_query_wizard_file__1.txt b/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_can_change_the_default_path_for_query_wizard_file__1.txt
deleted file mode 100644
index 5e3e6d7..0000000
--- a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_can_change_the_default_path_for_query_wizard_file__1.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_elastic_query_wizard_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_elastic_query_wizard_file_with_content__1.txt
deleted file mode 100644
index 9b4e72c..0000000
--- a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_elastic_query_wizard_file_with_content__1.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_eloquent_query_wizard_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_eloquent_query_wizard_file_with_content__1.txt
deleted file mode 100644
index f9f2802..0000000
--- a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_eloquent_query_wizard_file_with_content__1.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_model_query_wizard_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_model_query_wizard_file_with_content__1.txt
deleted file mode 100644
index b87717b..0000000
--- a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_model_query_wizard_file_with_content__1.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_scout_query_wizard_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_scout_query_wizard_file_with_content__1.txt
deleted file mode 100644
index 5fd6d63..0000000
--- a/tests/Commands/Generators/__snapshots__/QueryWizardMakeCommandTest__it_generated_correct_scout_query_wizard_file_with_content__1.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-
- */
- protected function allowedAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultAppends(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedFields(): array
- {
- return [
- // TODO: add fields here
- ];
- }
-
- /**
- * @return array
- */
- protected function allowedFilters(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultIncludes(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function allowedSorts(): array
- {
- return [];
- }
-
- /**
- * @return array
- */
- protected function defaultSorts(): array
- {
- return [];
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_change_the_default_namespace_for_api_request__1.txt b/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_change_the_default_namespace_for_api_request__1.txt
deleted file mode 100644
index 3acff3b..0000000
--- a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_change_the_default_namespace_for_api_request__1.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_api_delete_request_file__1.txt b/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_api_delete_request_file__1.txt
deleted file mode 100644
index 8ce9a82..0000000
--- a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_api_delete_request_file__1.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('model');
- return $model && Gate::check('delete', $model);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_api_list_request_file__1.txt b/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_api_list_request_file__1.txt
deleted file mode 100644
index 199d9c4..0000000
--- a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_api_list_request_file__1.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('model');
- return $model && Gate::check('update', $model);
- }
-
- public function toDTO(): TestDTO
- {
- return new TestDTO($this->validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_api_view_request_file__1.txt b/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_api_view_request_file__1.txt
deleted file mode 100644
index 4340ffa..0000000
--- a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_api_view_request_file__1.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('model');
- return $model && Gate::check('view', $model);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_web_create_request_file__1.txt b/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_web_create_request_file__1.txt
deleted file mode 100644
index 40d511b..0000000
--- a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_web_create_request_file__1.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_web_delete_request_file__1.txt b/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_web_delete_request_file__1.txt
deleted file mode 100644
index 56810b7..0000000
--- a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_web_delete_request_file__1.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-route('model');
- return $model && Gate::check('delete', $model);
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_web_update_request_file__1.txt b/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_web_update_request_file__1.txt
deleted file mode 100644
index 2eff23f..0000000
--- a/tests/Commands/Generators/__snapshots__/RequestMakeCommandTest__it_can_generate_web_update_request_file__1.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-route('model');
- return $model && Gate::check('update', $model);
- }
-
- public function toDTO(): TestDTO
- {
- return new TestDTO($this->validated());
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/ResourceMakeCommandTest__it_can_change_the_default_namespace_for_resource_file__1.txt b/tests/Commands/Generators/__snapshots__/ResourceMakeCommandTest__it_can_change_the_default_namespace_for_resource_file__1.txt
deleted file mode 100644
index 2cbda71..0000000
--- a/tests/Commands/Generators/__snapshots__/ResourceMakeCommandTest__it_can_change_the_default_namespace_for_resource_file__1.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-name('api.route.list');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_delete_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_delete_method__1.txt
deleted file mode 100644
index 3cd046c..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_delete_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.nested.some_delete_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_get_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_get_method__1.txt
deleted file mode 100644
index e5e9c98..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_get_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.nested.some_get_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_options_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_options_method__1.txt
deleted file mode 100644
index 73edd4c..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_options_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.nested.some_options_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_patch_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_patch_method__1.txt
deleted file mode 100644
index ad5b41c..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_patch_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.nested.some_patch_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_post_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_post_method__1.txt
deleted file mode 100644
index ee0c87d..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_post_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.nested.some_post_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_put_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_put_method__1.txt
deleted file mode 100644
index aedd372..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_api_route_with_put_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.nested.some_put_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_correct_route_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_correct_route_file_with_content__1.txt
deleted file mode 100644
index 0f966fd..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_correct_route_file_with_content__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.route.list');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_recognized_view_route__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_recognized_view_route__1.txt
deleted file mode 100644
index 556d6bc..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_recognized_view_route__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.posts.view');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_route_with_options_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_route_with_options_method__1.txt
deleted file mode 100644
index 73edd4c..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_route_with_options_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.nested.some_options_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_delete_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_delete_method__1.txt
deleted file mode 100644
index 4b7870c..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_delete_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('web.nested.some_delete_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_get_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_get_method__1.txt
deleted file mode 100644
index 6f99f2a..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_get_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('web.nested.some_get_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_options_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_options_method__1.txt
deleted file mode 100644
index 6fe1882..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_options_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('web.nested.some_options_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_patch_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_patch_method__1.txt
deleted file mode 100644
index 51601a0..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_patch_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('web.nested.some_patch_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_post_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_post_method__1.txt
deleted file mode 100644
index 1a0caa5..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_post_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('web.nested.some_post_route');
diff --git a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_put_method__1.txt b/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_put_method__1.txt
deleted file mode 100644
index c8df1cc..0000000
--- a/tests/Commands/Generators/__snapshots__/RouteMakeCommandTest__it_generated_web_route_with_put_method__1.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-name('web.nested.some_put_route');
diff --git a/tests/Commands/Generators/__snapshots__/RuleMakeCommandTest__it_can_change_the_default_namespace_for_rule_file__1.txt b/tests/Commands/Generators/__snapshots__/RuleMakeCommandTest__it_can_change_the_default_namespace_for_rule_file__1.txt
deleted file mode 100644
index 164e3fb..0000000
--- a/tests/Commands/Generators/__snapshots__/RuleMakeCommandTest__it_can_change_the_default_namespace_for_rule_file__1.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-handle(new CreatePermissionDTO(
- name: 'view-my-awesome-model',
- display_name: 'View any "my-awesome-models"',
- group: 'my-awesome-models'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'create-my-awesome-model',
- display_name: 'Create "my-awesome-models"',
- group: 'my-awesome-models'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'update-my-awesome-model',
- display_name: 'Update any "my-awesome-models"',
- group: 'my-awesome-models'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'delete-my-awesome-model',
- display_name: 'Delete any "my-awesome-models"',
- group: 'my-awesome-models'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'force-delete-my-awesome-model',
- display_name: 'Force delete any "my-awesome-models"',
- group: 'my-awesome-models'
- ));
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/SeederMakeCommandTest__it_generated_correct_plain_seeder_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/SeederMakeCommandTest__it_generated_correct_plain_seeder_file_with_content__1.txt
deleted file mode 100644
index 1856f3c..0000000
--- a/tests/Commands/Generators/__snapshots__/SeederMakeCommandTest__it_generated_correct_plain_seeder_file_with_content__1.txt
+++ /dev/null
@@ -1,13 +0,0 @@
- '',
- 'roles' => '',
- ];
-
- public function test(): void
- {
- //
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_change_the_default_namespace_for_cli_test__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_change_the_default_namespace_for_cli_test__1.txt
deleted file mode 100644
index 53d5a30..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_change_the_default_namespace_for_cli_test__1.txt
+++ /dev/null
@@ -1,17 +0,0 @@
- '',
- 'roles' => '',
- ];
-
- public function test(): void
- {
- //
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_change_the_default_path_for_cli_test__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_change_the_default_path_for_cli_test__1.txt
deleted file mode 100644
index 53d5a30..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_change_the_default_path_for_cli_test__1.txt
+++ /dev/null
@@ -1,17 +0,0 @@
- 'create-some-test-model',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_create_some_test_model(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->postJson(route('some.api.url'), $data)
- ->assertCreated()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->has('id')
- ->whereAll($data)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(SomeTestModel::class, $data);
- }
-
- public function test_create_some_test_model_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $data = $this->getTestData();
-
- $this->postJson(route('some.api.url'), $data)
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_delete_test_file__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_delete_test_file__1.txt
deleted file mode 100644
index c9e259f..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_delete_test_file__1.txt
+++ /dev/null
@@ -1,51 +0,0 @@
- 'delete-some-test-model',
- 'roles' => '',
- ];
-
- public function test_delete_some_test_model(): void
- {
- $this->getTestingUser();
-
- $someTestModel = SomeTestModel::factory()->create();
-
- $this->deleteJson(route('some.api.url', ['someTestModel' => $someTestModel->getKey()]))
- ->assertNoContent();
-
- $this->assertNull(SomeTestModel::find($someTestModel->getKey()));
- }
-
- public function test_delete_some_test_model_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $someTestModel = SomeTestModel::factory()->create();
-
- $this->deleteJson(route('some.api.url', ['someTestModel' => $someTestModel->getKey()]))
- ->assertForbidden();
- }
-
- public function test_delete_not_existing_some_test_model(): void
- {
- $this->getTestingUser();
-
- $this->deleteJson(route('some.api.url', ['someTestModel' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_list_test_file__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_list_test_file__1.txt
deleted file mode 100644
index b41bd37..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_list_test_file__1.txt
+++ /dev/null
@@ -1,47 +0,0 @@
- 'view-some-test-model',
- 'roles' => '',
- ];
-
- public function test_list_some_test_models(): void
- {
- $this->getTestingUser();
-
- SomeTestModel::factory()->count(2)->create();
-
- $this->getJson(route('some.api.url'))
- ->assertOk()
- ->assertJsonStructure([
- 'links',
- 'meta',
- 'data'
- ])
- ->assertJsonCount(SomeTestModel::query()->count(), 'data');
- }
-
- public function test_list_some_test_models_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- SomeTestModel::factory()->count(2)->create();
-
- $this->getJson(route('some.api.url'))
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_update_test_file__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_update_test_file__1.txt
deleted file mode 100644
index cf6c9bd..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_update_test_file__1.txt
+++ /dev/null
@@ -1,74 +0,0 @@
- 'update-some-test-model',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_update_some_test_model(): void
- {
- $this->getTestingUser();
-
- $someTestModel = SomeTestModel::factory()->create();
-
- $data = $this->getTestData();
- $expectedData = array_merge($data, [
- 'id' => $someTestModel->getKey(),
- ]);
-
- $this->patchJson(route('some.api.url', ['someTestModel' => $someTestModel->getKey()]), $data)
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
-
- $this->assertExistsModelWhereColumns(SomeTestModel::class, $expectedData);
- }
-
- public function test_update_some_test_model_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $someTestModel = SomeTestModel::factory()->create();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('some.api.url', ['someTestModel' => $someTestModel->getKey()]), $data)
- ->assertForbidden();
- }
-
- public function test_update_non_existing_some_test_model(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->patchJson(route('some.api.url', ['someTestModel' => 7777]), $data)
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_view_test_file__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_view_test_file__1.txt
deleted file mode 100644
index a6fc00d..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_api_view_test_file__1.txt
+++ /dev/null
@@ -1,57 +0,0 @@
- 'view-some-test-model',
- 'roles' => '',
- ];
-
- public function test_view_some_test_model(): void
- {
- $this->getTestingUser();
-
- $someTestModel = SomeTestModel::factory()->create();
- $expectedData = $someTestModel->toArray();
-
- $this->getJson(route('some.api.url', ['someTestModel' => $someTestModel->getKey()]))
- ->assertOk()
- ->assertJson(fn (AssertableJson $json) =>
- $json->has('data', fn (AssertableJson $json) =>
- $json->whereAll($expectedData)
- ->etc()
- )
- );
- }
-
- public function test_view_some_test_model_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $someTestModel = SomeTestModel::factory()->create();
-
- $this->getJson(route('some.api.url', ['someTestModel' => $someTestModel->getKey()]))
- ->assertForbidden();
- }
-
- public function test_view_not_existing_some_test_model(): void
- {
- $this->getTestingUser();
-
- $this->getJson(route('some.api.url', ['someTestModel' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_web_create_test_file__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_web_create_test_file__1.txt
deleted file mode 100644
index 1c808cf..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_web_create_test_file__1.txt
+++ /dev/null
@@ -1,50 +0,0 @@
- 'create-some-test-model',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_create_some_test_model(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->post(route('some.web.url'), $data)
- ->assertCreated();
-
- $this->assertExistsModelWhereColumns(SomeTestModel::class, $data);
- }
-
- public function test_create_some_test_model_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $data = $this->getTestData();
-
- $this->post(route('some.web.url'), $data)
- ->assertForbidden();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_web_delete_test_file__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_web_delete_test_file__1.txt
deleted file mode 100644
index db175a9..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_web_delete_test_file__1.txt
+++ /dev/null
@@ -1,51 +0,0 @@
- 'delete-some-test-model',
- 'roles' => '',
- ];
-
- public function test_delete_some_test_model(): void
- {
- $this->getTestingUser();
-
- $someTestModel = SomeTestModel::factory()->create();
-
- $this->delete(route('some.web.url', ['someTestModel' => $someTestModel->getKey()]))
- ->assertNoContent();
-
- $this->assertNull(SomeTestModel::find($someTestModel->getKey()));
- }
-
- public function test_delete_some_test_model_without_access(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $someTestModel = SomeTestModel::factory()->create();
-
- $this->delete(route('some.web.url', ['someTestModel' => $someTestModel->getKey()]))
- ->assertForbidden();
- }
-
- public function test_delete_not_existing_some_test_model(): void
- {
- $this->getTestingUser();
-
- $this->delete(route('some.web.url', ['someTestModel' => 7777]))
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_web_update_test_file__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_web_update_test_file__1.txt
deleted file mode 100644
index ebf43fa..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_can_generate_web_update_test_file__1.txt
+++ /dev/null
@@ -1,67 +0,0 @@
- 'update-some-test-model',
- 'roles' => '',
- ];
-
- protected function getTestData(array $mergeData = []): array
- {
- return array_merge([
- // TODO: add fields here
- ], $mergeData);
- }
-
- public function test_update_some_test_model(): void
- {
- $this->getTestingUser();
-
- $someTestModel = SomeTestModel::factory()->create();
-
- $data = $this->getTestData();
- $expectedData = array_merge($data, [
- 'id' => $someTestModel->getKey(),
- ]);
-
- $this->patch(route('some.web.url', ['someTestModel' => $someTestModel->getKey()]), $data)
- ->assertOk();
-
- $this->assertExistsModelWhereColumns(SomeTestModel::class, $expectedData);
- }
-
- public function test_update_some_test_modelWithoutAccess(): void
- {
- $this->getTestingUserWithoutAccess();
-
- $someTestModel = SomeTestModel::factory()->create();
-
- $data = $this->getTestData();
-
- $this->patch(route('some.web.url', ['someTestModel' => $someTestModel->getKey()]), $data)
- ->assertForbidden();
- }
-
- public function test_update_non_existing_some_test_model(): void
- {
- $this->getTestingUser();
-
- $data = $this->getTestData();
-
- $this->patch(route('some.web.url', ['someTestModel' => 7777]), $data)
- ->assertNotFound();
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_generated_correct_api_test_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_generated_correct_api_test_file_with_content__1.txt
deleted file mode 100644
index 42e323e..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_generated_correct_api_test_file_with_content__1.txt
+++ /dev/null
@@ -1,25 +0,0 @@
- '',
- 'roles' => '',
- ];
-
- public function test(): void
- {
- //
- }
-}
diff --git a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_generated_correct_cli_test_file_with_content__1.txt b/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_generated_correct_cli_test_file_with_content__1.txt
deleted file mode 100644
index a4ae95e..0000000
--- a/tests/Commands/Generators/__snapshots__/TestMakeCommandTest__it_generated_correct_cli_test_file_with_content__1.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-setModules([
+ __DIR__ . '/../fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/../fixtures/stubs/modules/valid/article',
+ __DIR__ . '/../fixtures/stubs/modules/valid/author',
+ __DIR__ . '/../fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/../fixtures/stubs/modules/valid/empty',
+ __DIR__ . '/../fixtures/stubs/modules/valid/navigation',
+ ], $this->app->basePath('/modules'));
+});
-use Laraneat\Modules\Contracts\RepositoryInterface;
-use Laraneat\Modules\Tests\BaseTestCase;
+it('outputs a table of modules', function () {
+ $this->artisan('module:list')
+ ->expectsTable(['Package Name', 'Namespace', 'Path'], [
+ ['laraneat/article-category', 'Modules\\ArticleCategory', $this->app->basePath('/modules/article-category')],
+ ['laraneat/article', 'Modules\\Article', $this->app->basePath('/modules/article')],
+ ['laraneat/author', 'Modules\\Author', $this->app->basePath('/modules/author')],
+ ['laraneat/empty', 'Modules\\Empty', $this->app->basePath('/modules/empty-module')],
+ ['empty/empty', 'Empty\\Empty', $this->app->basePath('/modules/empty')],
+ ['laraneat/location', 'Modules\\GeoLocation', $this->app->basePath('/modules/navigation')],
-/**
- * @group command
- */
-class ListCommandTest extends BaseTestCase
-{
- protected function setUp(): void
- {
- parent::setUp();
- $this->artisan('module:make', ['name' => 'Article']);
- }
-
- protected function tearDown(): void
- {
- $this->app[RepositoryInterface::class]->delete('Article');
- parent::tearDown();
- }
-
- /** @test */
- public function it_can_list_modules()
- {
- $code = $this->artisan('module:list');
-
- // We just want to make sure nothing throws an exception inside the list command
- $this->assertTrue(true);
- $this->assertSame(0, $code);
- }
-}
+ ])
+ ->assertSuccessful();
+});
diff --git a/tests/Commands/MigrateCommandTest.php b/tests/Commands/MigrateCommandTest.php
new file mode 100644
index 0000000..a477d21
--- /dev/null
+++ b/tests/Commands/MigrateCommandTest.php
@@ -0,0 +1,37 @@
+setModules([
+ __DIR__ . '/../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('runs migrations for the specified module', function () {
+ $this->artisan('module:migrate', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ ])
+ ->assertSuccessful();
+});
+
+it('requires confirmation in production', function () {
+ $this->app['env'] = 'production';
+
+ $this->artisan('module:migrate', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ ])
+ ->expectsConfirmation('Are you sure you want to run this command?', 'no')
+ ->assertFailed();
+});
+
+it('can be forced in production', function () {
+ $this->app['env'] = 'production';
+
+ $this->artisan('module:migrate', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ '--force' => true,
+ ])
+ ->assertSuccessful();
+});
diff --git a/tests/Commands/MigrateRefreshCommandTest.php b/tests/Commands/MigrateRefreshCommandTest.php
new file mode 100644
index 0000000..cfb0555
--- /dev/null
+++ b/tests/Commands/MigrateRefreshCommandTest.php
@@ -0,0 +1,37 @@
+setModules([
+ __DIR__ . '/../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('refreshes migrations for the specified module', function () {
+ $this->artisan('module:migrate:refresh', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ ])
+ ->assertSuccessful();
+});
+
+it('requires confirmation in production', function () {
+ $this->app['env'] = 'production';
+
+ $this->artisan('module:migrate:refresh', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ ])
+ ->expectsConfirmation('Are you sure you want to run this command?', 'no')
+ ->assertFailed();
+});
+
+it('can be forced in production', function () {
+ $this->app['env'] = 'production';
+
+ $this->artisan('module:migrate:refresh', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ '--force' => true,
+ ])
+ ->assertSuccessful();
+});
diff --git a/tests/Commands/MigrateResetCommandTest.php b/tests/Commands/MigrateResetCommandTest.php
new file mode 100644
index 0000000..9e8812f
--- /dev/null
+++ b/tests/Commands/MigrateResetCommandTest.php
@@ -0,0 +1,37 @@
+setModules([
+ __DIR__ . '/../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('resets migrations for the specified module', function () {
+ $this->artisan('module:migrate:reset', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ ])
+ ->assertSuccessful();
+});
+
+it('requires confirmation in production', function () {
+ $this->app['env'] = 'production';
+
+ $this->artisan('module:migrate:reset', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ ])
+ ->expectsConfirmation('Are you sure you want to run this command?', 'no')
+ ->assertFailed();
+});
+
+it('can be forced in production', function () {
+ $this->app['env'] = 'production';
+
+ $this->artisan('module:migrate:reset', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ '--force' => true,
+ ])
+ ->assertSuccessful();
+});
diff --git a/tests/Commands/MigrateRollbackCommandTest.php b/tests/Commands/MigrateRollbackCommandTest.php
new file mode 100644
index 0000000..9c07dba
--- /dev/null
+++ b/tests/Commands/MigrateRollbackCommandTest.php
@@ -0,0 +1,37 @@
+setModules([
+ __DIR__ . '/../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('rolls back migrations for the specified module', function () {
+ $this->artisan('module:migrate:rollback', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ ])
+ ->assertSuccessful();
+});
+
+it('requires confirmation in production', function () {
+ $this->app['env'] = 'production';
+
+ $this->artisan('module:migrate:rollback', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ ])
+ ->expectsConfirmation('Are you sure you want to run this command?', 'no')
+ ->assertFailed();
+});
+
+it('can be forced in production', function () {
+ $this->app['env'] = 'production';
+
+ $this->artisan('module:migrate:rollback', [
+ 'module' => 'Author',
+ '--pretend' => true,
+ '--force' => true,
+ ])
+ ->assertSuccessful();
+});
diff --git a/tests/Commands/MigrateStatusCommandTest.php b/tests/Commands/MigrateStatusCommandTest.php
new file mode 100644
index 0000000..457911e
--- /dev/null
+++ b/tests/Commands/MigrateStatusCommandTest.php
@@ -0,0 +1,24 @@
+setModules([
+ __DIR__ . '/../fixtures/stubs/modules/valid/author',
+ ], $this->app->basePath('/modules'));
+});
+
+it('shows migration status for the specified module', function () {
+ $this->artisan('module:migrate:status', [
+ 'module' => 'Author',
+ ])
+ ->assertSuccessful();
+});
+
+it('does not require confirmation in production', function () {
+ $this->app['env'] = 'production';
+
+ // migrate:status should not require confirmation as it's read-only
+ $this->artisan('module:migrate:status', [
+ 'module' => 'Author',
+ ])
+ ->assertSuccessful();
+});
diff --git a/tests/Commands/ModuleDeleteCommandTest.php b/tests/Commands/ModuleDeleteCommandTest.php
index 7e9b851..ac4e6c9 100644
--- a/tests/Commands/ModuleDeleteCommandTest.php
+++ b/tests/Commands/ModuleDeleteCommandTest.php
@@ -1,48 +1,44 @@
finder = $this->app['files'];
- $this->activator = new FileActivator($this->app);
- }
-
- /** @test */
- public function it_can_delete_a_module_from_disk(): void
- {
- $this->artisan('module:make', ['name' => 'WrongModule']);
- $this->assertDirectoryExists(base_path('app/Modules/WrongModule'));
-
- $code = $this->artisan('module:delete', ['module' => 'WrongModule']);
- $this->assertDirectoryDoesNotExist(base_path('app/Modules/WrongModule'));
- $this->assertSame(0, $code);
- }
-
- /** @test */
- public function it_deletes_modules_from_status_file(): void
- {
- $this->artisan('module:make', ['name' => 'WrongModule']);
- $this->assertMatchesSnapshot($this->finder->get($this->activator->getStatusesFilePath()));
-
- $code = $this->artisan('module:delete', ['module' => 'WrongModule']);
- $this->assertMatchesSnapshot($this->finder->get($this->activator->getStatusesFilePath()));
- $this->assertSame(0, $code);
- }
-}
+use Laraneat\Modules\ModulesRepository;
+use Laraneat\Modules\Support\Composer;
+
+beforeEach(function () {
+ // Set mock BEFORE anything else so Module instances get the mock
+ $this->instance(Composer::class, $this->mockComposer(['removePackages' => true]));
+
+ // Rebind ModulesRepository with the mocked Composer
+ $this->app->singleton(ModulesRepository::class, function ($app) {
+ return new ModulesRepository(
+ filesystem: $app['files'],
+ composer: $app[Composer::class],
+ modulesPath: $app['config']->get('modules.path'),
+ basePath: $app->basePath(),
+ modulesManifestPath: $app['config']->get('modules.cache.enabled')
+ ? $app->bootstrapPath('cache/laraneat-modules.php')
+ : null
+ );
+ });
+
+ $this->setModules([
+ __DIR__ . '/../fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/../fixtures/stubs/modules/valid/article',
+ __DIR__ . '/../fixtures/stubs/modules/valid/author',
+ __DIR__ . '/../fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/../fixtures/stubs/modules/valid/empty',
+ __DIR__ . '/../fixtures/stubs/modules/valid/navigation',
+ ], $this->app->basePath('/modules'));
+
+ /** @var ModulesRepository $modulesRepository */
+ $modulesRepository = $this->app[ModulesRepository::class];
+ $this->modulesRepository = $modulesRepository;
+});
+
+it('deletes a module', function () {
+ expect($this->modulesRepository->has('laraneat/article'))->toBe(true);
+
+ $this->artisan('module:delete article')
+ ->assertSuccessful();
+
+ expect($this->modulesRepository->has('laraneat/article'))->toBe(false);
+});
diff --git a/tests/Commands/StubPublishCommandTest.php b/tests/Commands/StubPublishCommandTest.php
new file mode 100644
index 0000000..482dd3f
--- /dev/null
+++ b/tests/Commands/StubPublishCommandTest.php
@@ -0,0 +1,18 @@
+customStubsPath = $this->app['config']->get('modules.custom_stubs');
+});
+
+afterEach(function () {
+ $this->filesystem->deleteDirectory($this->customStubsPath);
+});
+
+it('publish all laraneat/modules stubs', function () {
+ $this->artisan('module:stub:publish')
+ ->assertSuccessful();
+
+ assertMatchesSnapshot(getRelativeFilePathsInDirectory($this->customStubsPath));
+});
diff --git a/tests/Commands/SyncCommandTest.php b/tests/Commands/SyncCommandTest.php
new file mode 100644
index 0000000..1726444
--- /dev/null
+++ b/tests/Commands/SyncCommandTest.php
@@ -0,0 +1,62 @@
+mock(ModulesRepository::class, function (MockInterface $mock) {
+ $mock->shouldReceive('pruneModulesManifest')->once();
+ $mock->shouldReceive('syncWithComposer')->once();
+ });
+
+ $this->artisan('module:sync')
+ ->expectsOutputToContain('Modules completed successfully!')
+ ->assertSuccessful();
+});
+
+it('handles ModuleHasNoNamespace exception', function () {
+ $this->mock(ModulesRepository::class, function (MockInterface $mock) {
+ $mock->shouldReceive('pruneModulesManifest')->once();
+ $mock->shouldReceive('syncWithComposer')->once()->andThrow(
+ ModuleHasNoNamespace::make('test/module')
+ );
+ });
+
+ $this->artisan('module:sync')
+ ->expectsOutputToContain('No namespace specified for module')
+ ->assertSuccessful();
+});
+
+it('handles ModuleHasNonUniquePackageName exception', function () {
+ $this->mock(ModulesRepository::class, function (MockInterface $mock) {
+ $mock->shouldReceive('pruneModulesManifest')->once();
+ $mock->shouldReceive('syncWithComposer')->once()->andThrow(
+ ModuleHasNonUniquePackageName::make('test/module', ['/path1', '/path2'])
+ );
+ });
+
+ $this->artisan('module:sync')
+ ->expectsOutputToContain('test/module')
+ ->assertSuccessful();
+});
+
+it('handles ComposerException and shows manual update hint', function () {
+ $this->mock(ModulesRepository::class, function (MockInterface $mock) {
+ $mock->shouldReceive('pruneModulesManifest')->once();
+ $mock->shouldReceive('syncWithComposer')->once()->andThrow(
+ ComposerException::make('Failed to update package with composer.')
+ );
+ $mock->shouldReceive('getModules')->once()->andReturn([
+ 'test/module-a' => (object) [],
+ 'test/module-b' => (object) [],
+ ]);
+ });
+
+ $this->artisan('module:sync')
+ ->expectsOutputToContain('Failed to update package with composer')
+ ->expectsOutputToContain('composer update test/module-a test/module-b')
+ ->assertSuccessful();
+});
diff --git a/tests/Commands/__snapshots__/ModuleDeleteCommandTest__it_deletes_modules_from_status_file__1.txt b/tests/Commands/__snapshots__/ModuleDeleteCommandTest__it_deletes_modules_from_status_file__1.txt
deleted file mode 100644
index e817d83..0000000
--- a/tests/Commands/__snapshots__/ModuleDeleteCommandTest__it_deletes_modules_from_status_file__1.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "WrongModule": true
-}
\ No newline at end of file
diff --git a/tests/Commands/__snapshots__/ModuleDeleteCommandTest__it_deletes_modules_from_status_file__2.txt b/tests/Commands/__snapshots__/ModuleDeleteCommandTest__it_deletes_modules_from_status_file__2.txt
deleted file mode 100644
index 0637a08..0000000
--- a/tests/Commands/__snapshots__/ModuleDeleteCommandTest__it_deletes_modules_from_status_file__2.txt
+++ /dev/null
@@ -1 +0,0 @@
-[]
\ No newline at end of file
diff --git a/tests/FileRepositoryTest.php b/tests/FileRepositoryTest.php
deleted file mode 100644
index ff0b227..0000000
--- a/tests/FileRepositoryTest.php
+++ /dev/null
@@ -1,227 +0,0 @@
-repository = new FileRepository($this->app);
- $this->activator = $this->app[ActivatorInterface::class];
- }
-
- protected function tearDown(): void
- {
- $this->activator->reset();
- parent::tearDown();
- }
-
- /** @test */
- public function it_adds_location_to_paths()
- {
- $this->repository->addLocation('some/path');
-
- $paths = $this->repository->getPaths();
- $this->assertCount(1, $paths);
- $this->assertEquals('some/path', $paths[0]);
- }
-
- /** @test */
- public function it_returns_all_enabled_modules()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->assertCount(0, $this->repository->getByStatus(true));
- $this->assertCount(0, $this->repository->allEnabled());
- }
-
- /** @test */
- public function it_returns_all_disabled_modules()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->assertCount(2, $this->repository->getByStatus(false));
- $this->assertCount(2, $this->repository->allDisabled());
- }
-
- /** @test */
- public function it_counts_all_modules()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->assertEquals(2, $this->repository->count());
- }
-
- /** @test */
- public function it_finds_a_module()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->assertInstanceOf(Module::class, $this->repository->find('article'));
- }
-
- /** @test */
- public function it_finds_a_module_by_alias()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->assertInstanceOf(Module::class, $this->repository->findByAlias('article'));
- $this->assertInstanceOf(Module::class, $this->repository->findByAlias('required_module'));
- }
-
- /** @test */
- public function it_find_or_fail_throws_exception_if_module_not_found()
- {
- $this->expectException(ModuleNotFoundException::class);
-
- $this->repository->findOrFail('something');
- }
-
- /** @test */
- public function it_finds_the_module_asset_path()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid/Article');
- $assetPath = $this->repository->assetPath('article');
-
- $this->assertEquals(public_path('modules/article'), $assetPath);
- }
-
- /** @test */
- public function it_gets_the_used_storage_path()
- {
- $path = $this->repository->getUsedStoragePath();
-
- $this->assertEquals(storage_path('app/modules/modules.used'), $path);
- }
-
- /** @test */
- public function it_sets_used_module()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->repository->setUsed('Article');
-
- $this->assertEquals('Article', $this->repository->getUsedNow());
- }
-
- /** @test */
- public function it_gets_the_assets_path()
- {
- $this->assertEquals(public_path('modules'), $this->repository->getAssetsPath());
- }
-
- /** @test */
- public function it_gets_a_specific_module_asset()
- {
- $path = $this->repository->asset('article:test.js');
-
- $this->assertEquals('//localhost/modules/article/test.js', $path);
- }
-
- /** @test */
- public function it_throws_exception_if_module_is_omitted()
- {
- $this->expectException(InvalidAssetPath::class);
- $this->expectExceptionMessage('Module name was not specified in asset [test.js].');
-
- $this->repository->asset('test.js');
- }
-
- /** @test */
- public function it_can_detect_if_module_is_active()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->repository->enable('Article');
-
- $this->assertTrue($this->repository->isEnabled('Article'));
- }
-
- /** @test */
- public function it_can_detect_if_module_is_inactive()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->repository->isDisabled('Article');
-
- $this->assertTrue($this->repository->isDisabled('Article'));
- }
-
- /** @test */
- public function it_can_disabled_a_module()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->repository->disable('Article');
-
- $this->assertTrue($this->repository->isDisabled('Article'));
- }
-
- /** @test */
- public function it_can_enable_a_module()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $this->repository->enable('Article');
-
- $this->assertTrue($this->repository->isEnabled('Article'));
- }
-
- /** @test */
- public function it_can_delete_a_module()
- {
- $this->artisan('module:make', ['name' => 'Article']);
-
- $this->repository->delete('Article');
-
- $this->assertDirectoryDoesNotExist(base_path('app/Modules/Article'));
- }
-
- /** @test */
- public function it_can_find_all_requirements_of_a_module()
- {
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
-
- $requirements = $this->repository->findRequirements('Article');
-
- $this->assertCount(1, $requirements);
- $this->assertInstanceOf(Module::class, $requirements[0]);
- }
-
- /** @test */
- public function it_can_register_macros()
- {
- Module::macro('registeredMacro', function () {});
-
- $this->assertTrue(Module::hasMacro('registeredMacro'));
- }
-
- /** @test */
- public function it_does_not_have_unregistered_macros()
- {
- $this->assertFalse(Module::hasMacro('unregisteredMacro'));
- }
-
- /** @test */
- public function it_calls_macros_on_modules()
- {
- Module::macro('getReverseName', function () {
- return strrev($this->getName());
- });
-
- $this->repository->addLocation(__DIR__ . '/fixtures/stubs/valid');
- $module = $this->repository->find('article');
-
- $this->assertEquals('elcitrA', $module->getReverseName());
- }
-}
diff --git a/tests/GeneratorHelperReaderTest.php b/tests/GeneratorHelperReaderTest.php
deleted file mode 100644
index 59d8aa3..0000000
--- a/tests/GeneratorHelperReaderTest.php
+++ /dev/null
@@ -1,93 +0,0 @@
-finder = $this->app['files'];
- $this->modulePath = base_path('app/Modules/Article');
- }
-
- private function makeModule(): void
- {
- $this->artisan('module:make', ['name' => 'Article']);
- }
-
- private function removeModule(): void
- {
- $this->finder->deleteDirectory($this->modulePath);
- }
-
- /** @test */
- public function it_can_read_component_configuration()
- {
- $seedConfig = GeneratorHelper::component('seeder');
-
- $this->assertEquals('Data/Seeders', $seedConfig->getPath());
- $this->assertEquals('Data\\Seeders', $seedConfig->getNamespace());
- $this->assertTrue($seedConfig->generate());
- $this->assertFalse($seedConfig->withGitKeep());
- }
-
- /** @test */
- public function it_can_guess_namespace_from_path()
- {
- $this->app['config']->set('modules.generator.components.provider', [
- 'path' => 'Base/Providers',
- 'generate' => true,
- 'gitkeep' => true
- ]);
-
- $config = GeneratorHelper::component('provider');
-
- $this->assertEquals('Base/Providers', $config->getPath());
- $this->assertEquals('Base\\Providers', $config->getNamespace());
- $this->assertTrue($config->generate());
- $this->assertTrue($config->withGitKeep());
- }
-
- /** @test */
- public function it_can_read_component_full_path_by_existing_module()
- {
- $this->makeModule();
- $resourceFullPath = GeneratorHelper::component('api-resource')->getFullPath('Article');
-
- $this->assertEquals(base_path('app/Modules/Article/UI/API/Resources'), $resourceFullPath);
- $this->removeModule();
- }
-
- /** @test */
- public function it_can_read_component_full_namespace_by_existing_module()
- {
- $this->makeModule();
- $resourceFullNamespace = GeneratorHelper::component('api-resource')->getFullNamespace('Article');
-
- $this->assertEquals('App\\Modules\\Article\\UI\\API\\Resources', $resourceFullNamespace);
- $this->removeModule();
- }
-
- /** @test */
- public function it_can_read_component_full_path_by_not_existing_module()
- {
- $resourceFullPath = GeneratorHelper::component('api-resource')->getFullPath('SomeModule');
-
- $this->assertEquals(base_path('app/Modules/SomeModule/UI/API/Resources'), $resourceFullPath);
- }
-
- /** @test */
- public function it_can_read_component_full_namespace_by_not_existing_module()
- {
- $resourceFullNamespace = GeneratorHelper::component('api-resource')->getFullNamespace('SomeModule');
-
- $this->assertEquals('App\\Modules\\SomeModule\\UI\\API\\Resources', $resourceFullNamespace);
- }
-}
diff --git a/tests/HelpersTest.php b/tests/HelpersTest.php
deleted file mode 100644
index 9551de0..0000000
--- a/tests/HelpersTest.php
+++ /dev/null
@@ -1,38 +0,0 @@
-modulePath = base_path('app/Modules/Article');
- $this->finder = $this->app['files'];
- $this->artisan('module:make', ['name' => 'Article']);
- }
-
- protected function tearDown(): void
- {
- $this->finder->deleteDirectory($this->modulePath);
- parent::tearDown();
- }
-
- /** @test */
- public function it_finds_the_module_path()
- {
- $this->assertTrue(Str::contains(module_path('Article'), 'app/Modules/Article'));
- }
-
- /** @test */
- public function it_can_bind_a_relative_path_to_module_path()
- {
- $this->assertTrue(Str::contains(module_path('Article', 'config/config.php'), 'app/Modules/Article/config/config.php'));
- }
-}
diff --git a/tests/JsonTest.php b/tests/JsonTest.php
deleted file mode 100644
index 2bffbec..0000000
--- a/tests/JsonTest.php
+++ /dev/null
@@ -1,133 +0,0 @@
-json = new Json($path, $this->app['files']);
- }
-
- /** @test */
- public function it_gets_the_file_path()
- {
- $path = __DIR__ . '/fixtures/stubs/valid/module.json';
-
- $this->assertEquals($path, $this->json->getPath());
- }
-
- /** @test */
- public function it_throws_an_exception_with_invalid_json()
- {
- $path = __DIR__ . '/fixtures/stubs/InvalidJsonModule/module.json';
-
- $this->expectException(JsonException::class);
-
- new Json($path, $this->app['files']);
- }
-
- /** @test */
- public function it_gets_attributes_from_json_file()
- {
- $this->assertEquals('Order', $this->json->get('name'));
- $this->assertEquals('order', $this->json->get('alias'));
- $this->assertEquals('My demo module', $this->json->get('description'));
- $this->assertEquals('0.1', $this->json->get('version'));
- $this->assertEquals(['my', 'stub', 'module'], $this->json->get('keywords'));
- $this->assertEquals(1, $this->json->get('active'));
- $this->assertEquals(1, $this->json->get('order'));
- }
-
- /** @test */
- public function it_reads_attributes_from_magic_get_method()
- {
- $this->assertEquals('Order', $this->json->name);
- $this->assertEquals('order', $this->json->alias);
- $this->assertEquals('My demo module', $this->json->description);
- $this->assertEquals('0.1', $this->json->version);
- $this->assertEquals(['my', 'stub', 'module'], $this->json->keywords);
- $this->assertEquals(1, $this->json->active);
- $this->assertEquals(1, $this->json->order);
- }
-
- /** @test */
- public function it_sets_a_path()
- {
- $path = __DIR__ . '/fixtures/stubs/valid/module.json';
- $this->assertEquals($path, $this->json->getPath());
-
- $this->json->setPath('some/path.json');
- $this->assertEquals('some/path.json', $this->json->getPath());
- }
-
- /** @test */
- public function it_decodes_json()
- {
- $expected = '{
- "name": "Order",
- "alias": "order",
- "namespace": "App\\\\Modules",
- "description": "My demo module",
- "version": "0.1",
- "keywords": [
- "my",
- "stub",
- "module"
- ],
- "active": 1,
- "order": 1,
- "providers": [
- "App\\\\Modules\\\\Order\\\\Providers\\\\OrderServiceProvider",
- "App\\\\Modules\\\\Order\\\\Providers\\\\EventServiceProvider",
- "App\\\\Modules\\\\Order\\\\Providers\\\\RouteServiceProvider"
- ],
- "aliases": [],
- "files": []
-}';
- $this->assertEquals($expected, $this->json->toJsonPretty());
- }
-
- /** @test */
- public function it_sets_a_key_value()
- {
- $this->json->set('key', 'value');
-
- $this->assertEquals('value', $this->json->get('key'));
- }
-
- /** @test */
- public function it_can_be_casted_to_string()
- {
- $expected = '{
- "name": "Order",
- "alias": "order",
- "namespace": "App\\\\Modules",
- "description": "My demo module",
- "version": "0.1",
- "keywords": [
- "my",
- "stub",
- "module"
- ],
- "active": 1,
- "order": 1,
- "providers": [
- "App\\\\Modules\\\\Order\\\\Providers\\\\OrderServiceProvider",
- "App\\\\Modules\\\\Order\\\\Providers\\\\EventServiceProvider",
- "App\\\\Modules\\\\Order\\\\Providers\\\\RouteServiceProvider"
- ],
- "aliases": [],
- "files": []
-}
-';
- $this->assertEquals($expected, (string)$this->json);
- }
-}
diff --git a/tests/ModuleTest.php b/tests/ModuleTest.php
index 9db67bd..1b49a92 100644
--- a/tests/ModuleTest.php
+++ b/tests/ModuleTest.php
@@ -1,246 +1,272 @@
module = new TestingModule(
- $this->app,
- 'Article Name',
- __DIR__ . '/fixtures/stubs/valid/Article',
- 'App\\Modules\\Article'
- );
- $this->activator = $this->app[ActivatorInterface::class];
- }
-
- protected function tearDown(): void
- {
- $this->activator->reset();
- parent::tearDown();
- }
-
- public static function setUpBeforeClass(): void
- {
- parent::setUpBeforeClass();
- symlink(__DIR__ . '/fixtures/stubs/valid', __DIR__ . '/fixtures/stubs/valid_symlink');
- }
-
- public static function tearDownAfterClass(): void
- {
- parent::tearDownAfterClass();
- unlink(__DIR__ . '/fixtures/stubs/valid_symlink');
- }
-
- /** @test */
- public function it_gets_module_name()
- {
- $this->assertEquals('Article Name', $this->module->getName());
- }
-
- /** @test */
- public function it_gets_module_key()
- {
- $this->assertEquals('article-name', $this->module->getKey());
- }
-
- /** @test */
- public function it_gets_studly_name()
- {
- $this->assertEquals('ArticleName', $this->module->getStudlyName());
- }
-
- /** @test */
- public function it_gets_snake_name()
- {
- $this->assertEquals('article_name', $this->module->getSnakeName());
- }
-
- /** @test */
- public function it_gets_module_description()
- {
- $this->assertEquals('article module', $this->module->getDescription());
- }
-
- /** @test */
- public function it_gets_module_alias()
- {
- $this->assertEquals('article', $this->module->getAlias());
- }
-
- /** @test */
- public function it_gets_module_path()
- {
- $this->assertEquals(__DIR__ . '/fixtures/stubs/valid/Article', $this->module->getPath());
- }
-
- /** @test */
- public function it_gets_module_path_with_symlink()
- {
- // symlink created in setUpBeforeClass
-
- $this->module = new TestingModule(
- $this->app,
- 'Article Name',
- __DIR__ . '/fixtures/stubs/valid_symlink/Article',
- 'App\\Module\\Article'
- );
-
- $this->assertEquals(__DIR__ . '/fixtures/stubs/valid_symlink/Article', $this->module->getPath());
-
- // symlink deleted in tearDownAfterClass
- }
-
- /** @test */
- public function it_gets_required_modules()
- {
- $this->assertEquals(['required_module'], $this->module->getRequires());
- }
-
- /** @test */
- public function it_reads_module_json_files()
- {
- $jsonModule = $this->module->json();
- $composerJson = $this->module->json('composer.json');
-
- $this->assertEquals('0.1', $jsonModule->get('version'));
- $this->assertEquals('laraneat/article', $composerJson->get('name'));
- }
-
- /** @test */
- public function it_reads_key_from_module_json_file_via_helper_method()
- {
- $this->assertEquals('Article', $this->module->get('name'));
- $this->assertEquals('0.1', $this->module->get('version'));
- $this->assertEquals('my default', $this->module->get('some-thing-non-there', 'my default'));
- $this->assertEquals(['required_module'], $this->module->get('requires'));
- }
-
- /** @test */
- public function it_reads_key_from_composer_json_file_via_helper_method()
- {
- $this->assertEquals('laraneat/article', $this->module->getComposerAttr('name'));
- }
-
- /** @test */
- public function it_casts_module_to_string()
- {
- $this->assertEquals('ArticleName', (string) $this->module);
- }
-
- /** @test */
- public function it_module_status_check()
- {
- $this->assertFalse($this->module->isStatus(true));
- $this->assertTrue($this->module->isStatus(false));
- }
-
- /** @test */
- public function it_checks_module_enabled_status()
- {
- $this->assertFalse($this->module->isEnabled());
- $this->assertTrue($this->module->isDisabled());
- }
-
- /** @test */
- public function it_sets_active_status(): void
- {
- $this->module->setActive(true);
- $this->assertTrue($this->module->isEnabled());
- $this->module->setActive(false);
- $this->assertFalse($this->module->isEnabled());
- }
-
- /** @test */
- public function it_fires_events_when_module_is_enabled()
- {
- Event::fake();
-
- $this->module->enable();
-
- Event::assertDispatched(sprintf('modules.%s.enabling', $this->module->getKey()));
- Event::assertDispatched(sprintf('modules.%s.enabled', $this->module->getKey()));
- }
-
- /** @test */
- public function it_fires_events_when_module_is_disabled()
- {
- Event::fake();
-
- $this->module->disable();
-
- Event::assertDispatched(sprintf('modules.%s.disabling', $this->module->getKey()));
- Event::assertDispatched(sprintf('modules.%s.disabled', $this->module->getKey()));
- }
-
- /** @test */
- public function it_has_a_good_providers_manifest_path()
- {
- $this->assertEquals(
- $this->app->bootstrapPath("cache/{$this->module->getSnakeName()}_module.php"),
- $this->module->getCachedServicesPath()
- );
- }
-
- /** @test */
- public function it_makes_a_manifest_file_when_providers_are_loaded()
- {
- $cachedServicesPath = $this->module->getCachedServicesPath();
-
- @unlink($cachedServicesPath);
- $this->assertFileDoesNotExist($cachedServicesPath);
-
- $this->module->registerProviders();
-
- $this->assertFileExists($cachedServicesPath);
- $manifest = require $cachedServicesPath;
-
- $this->assertEquals([
- 'providers' => [
- ArticleServiceProvider::class,
- DeferredServiceProvider::class,
- ],
- 'eager' => [ArticleServiceProvider::class],
- 'deferred' => ['deferred' => DeferredServiceProvider::class],
- 'when' =>
- [DeferredServiceProvider::class => []],
- ], $manifest);
- }
-
- /** @test */
- public function it_can_load_a_deferred_provider()
- {
- @unlink($this->module->getCachedServicesPath());
-
- $this->module->registerProviders();
-
- try {
- app('foo');
- $this->fail("app('foo') should throw an exception.");
- } catch (\Exception $e) {
- $this->assertEquals('Target class [foo] does not exist.', $e->getMessage());
- }
-
- app('deferred');
-
- $this->assertEquals('bar', app('foo'));
- }
-}
-
-class TestingModule extends \Laraneat\Modules\Module
-{
- public function registerProviders(): void
- {
- parent::registerProviders();
- }
-}
+use Laraneat\Modules\Support\ModuleConfigWriter;
+
+use function PHPUnit\Framework\assertFileExists;
+use function Spatie\Snapshots\assertMatchesFileSnapshot;
+
+it('can return the package name', function () {
+ expect($this->createModule(['packageName' => 'some-vendor/testing-module'])->getPackageName())->toBe('some-vendor/testing-module');
+ expect($this->createModule(['packageName' => 'testing-module'])->getPackageName())->toBe('testing-module');
+ expect($this->createModule(['packageName' => ' some-vendor/module '])->getPackageName())->toBe('some-vendor/module');
+});
+
+it('can return the name', function () {
+ expect($this->createModule(['name' => 'TestingModule'])->getName())->toBe('TestingModule');
+ expect($this->createModule(['name' => ' SomeModule '])->getName())->toBe('SomeModule');
+ expect($this->createModule(['name' => ' some-module '])->getName())->toBe('some-module');
+
+ expect($this->createModule(['packageName' => 'some-vendor/testing-module'])->getName())->toBe('testing-module');
+ expect($this->createModule(['packageName' => ' some-vendor/module '])->getName())->toBe('module');
+ expect($this->createModule(['packageName' => 'testing-module'])->getName())->toBe('testing-module');
+});
+
+it('can return the studly name', function () {
+ expect($this->createModule(['name' => 'TestingModule'])->getStudlyName())->toBe('TestingModule');
+ expect($this->createModule(['name' => ' SomeModule '])->getStudlyName())->toBe('SomeModule');
+ expect($this->createModule(['name' => ' some-module '])->getStudlyName())->toBe('SomeModule');
+
+ expect($this->createModule(['packageName' => 'some-vendor/testing-module'])->getStudlyName())->toBe('TestingModule');
+ expect($this->createModule(['packageName' => ' some-vendor/module '])->getStudlyName())->toBe('Module');
+ expect($this->createModule(['packageName' => 'testing-module'])->getStudlyName())->toBe('TestingModule');
+});
+
+it('can return the kebab name', function () {
+ expect($this->createModule(['name' => 'TestingModule'])->getKebabName())->toBe('testing-module');
+ expect($this->createModule(['name' => ' SomeModule '])->getKebabName())->toBe('some-module');
+ expect($this->createModule(['name' => ' some-module '])->getKebabName())->toBe('some-module');
+
+ expect($this->createModule(['packageName' => 'some-vendor/testing-module'])->getKebabName())->toBe('testing-module');
+ expect($this->createModule(['packageName' => ' some-vendor/module '])->getKebabName())->toBe('module');
+ expect($this->createModule(['packageName' => 'testing-module'])->getKebabName())->toBe('testing-module');
+});
+
+it('can return the snake name', function () {
+ expect($this->createModule(['name' => 'TestingModule'])->getSnakeName())->toBe('testing_module');
+ expect($this->createModule(['name' => ' SomeModule '])->getSnakeName())->toBe('some_module');
+ expect($this->createModule(['name' => ' some-module '])->getSnakeName())->toBe('some_module');
+
+ expect($this->createModule(['packageName' => 'some-vendor/testing-module'])->getSnakeName())->toBe('testing_module');
+ expect($this->createModule(['packageName' => ' some-vendor/module '])->getSnakeName())->toBe('module');
+ expect($this->createModule(['packageName' => 'testing-module'])->getSnakeName())->toBe('testing_module');
+});
+
+it('can return the path', function () {
+ expect($this->createModule([
+ 'path' => $this->app->basePath('/modules/SomeTestingModule'),
+ ])->getPath())->toBe($this->app->basePath('/modules/SomeTestingModule'));
+});
+
+it('can return the namespace', function () {
+ expect($this->createModule(['namespace' => 'Some\\TestingModule\\'])->getNamespace())
+ ->toBe('Some\\TestingModule');
+ expect($this->createModule(['namespace' => 'Some\\TestingModule\\\\\\'])->getNamespace())
+ ->toBe('Some\\TestingModule');
+ expect($this->createModule(['namespace' => '\\\\Some\\TestingModule'])->getNamespace())
+ ->toBe('Some\\TestingModule');
+ expect($this->createModule(['namespace' => '\\\\Some\\TestingModule\\\\\\'])->getNamespace())
+ ->toBe('Some\\TestingModule');
+});
+
+it('can return providers', function () {
+ expect($this->createModule([
+ 'providers' => [
+ 'SomeVendor\\TestingModule\\Providers\\TestingModuleServiceProvider',
+ 'SomeVendor\\TestingModule\\Providers\\RouteServiceProvider',
+ ],
+ ])->getProviders())->toBe([
+ 'SomeVendor\\TestingModule\\Providers\\TestingModuleServiceProvider',
+ 'SomeVendor\\TestingModule\\Providers\\RouteServiceProvider',
+ ]);
+});
+
+it('can return aliases', function () {
+ expect($this->createModule([
+ 'aliases' => [
+ 'testing-module' => 'SomeVendor\\TestingModule\\Facades\\TestingModule',
+ 'some' => 'SomeVendor\\TestingModule\\Facades\\Some',
+ ],
+ ])->getAliases())->toBe([
+ 'testing-module' => 'SomeVendor\\TestingModule\\Facades\\TestingModule',
+ 'some' => 'SomeVendor\\TestingModule\\Facades\\Some',
+ ]);
+});
+
+it('can make sub path', function () {
+ expect($this->createModule(['path' => $this->app->basePath('/modules/SomeTestingModule')])
+ ->subPath('resources/views/index.blade.php'))
+ ->toBe($this->app->basePath('/modules/SomeTestingModule/resources/views/index.blade.php'));
+
+ expect($this->createModule(['path' => $this->app->basePath('/modules/SomeTestingModule')])
+ ->subPath('///resources/views/index.blade.php'))
+ ->toBe($this->app->basePath('/modules/SomeTestingModule/resources/views/index.blade.php'));
+});
+
+it('can make sub namespace', function () {
+ expect($this->createModule(['namespace' => 'SomeVendor\\SomeTestingModule'])
+ ->subNamespace('Models\\SomeModel'))
+ ->toBe('SomeVendor\\SomeTestingModule\\Models\\SomeModel');
+
+ expect($this->createModule(['namespace' => 'SomeVendor\\SomeTestingModule'])
+ ->subNamespace('\\\\Models\\SomeModel\\\\'))
+ ->toBe('SomeVendor\\SomeTestingModule\\Models\\SomeModel');
+});
+
+it('can return module as array', function () {
+ expect($this->createModule([
+ 'path' => $this->app->basePath('modules/TestingModule'),
+ 'packageName' => 'some-vendor/testing-module',
+ 'name' => 'TestingModule',
+ 'namespace' => '\\\\\\SomeVendor\\TestingModule\\\\',
+ 'providers' => [
+ 'SomeVendor\\TestingModule\\Providers\\TestingModuleServiceProvider',
+ 'SomeVendor\\TestingModule\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [
+ 'testing-module' => 'SomeVendor\\TestingModule\\Facades\\TestingModule',
+ 'some' => 'SomeVendor\\TestingModule\\Facades\\Some',
+ ],
+ ])->toArray())->toBe([
+ 'path' => $this->app->basePath('modules/TestingModule'),
+ 'packageName' => 'some-vendor/testing-module',
+ 'name' => 'TestingModule',
+ 'namespace' => 'SomeVendor\\TestingModule',
+ 'providers' => [
+ 'SomeVendor\\TestingModule\\Providers\\TestingModuleServiceProvider',
+ 'SomeVendor\\TestingModule\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [
+ 'testing-module' => 'SomeVendor\\TestingModule\\Facades\\TestingModule',
+ 'some' => 'SomeVendor\\TestingModule\\Facades\\Some',
+ ],
+ ]);
+});
+
+it('can update providers via ModuleConfigWriter', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ ]);
+
+ $module = $this->createModule([
+ 'path' => $this->app->basePath('/modules/author'),
+ 'packageName' => 'laraneat/author',
+ 'name' => 'author',
+ 'namespace' => 'Modules\\Author',
+ 'providers' => [
+ 'Modules\\Author\\Providers\\AuthorServiceProvider',
+ 'Modules\\Author\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [
+ 'AuthorFacade' => 'Modules\\Author\\Facades\\SomeFacade',
+ ],
+ ]);
+
+ $composerJsonPath = $module->subPath('composer.json');
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+
+ /** @var ModuleConfigWriter $configWriter */
+ $configWriter = $this->app->make(ModuleConfigWriter::class);
+ $configWriter->updateProviders($module, [
+ 'Modules\\Author\\Providers\\FooServiceProvider',
+ 'Modules\\Foo\\Providers\\BarServiceProvider',
+ ]);
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+});
+
+it('can update aliases via ModuleConfigWriter', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ ]);
+
+ $module = $this->createModule([
+ 'path' => $this->app->basePath('/modules/author'),
+ 'packageName' => 'laraneat/author',
+ 'name' => 'author',
+ 'namespace' => 'Modules\\Author',
+ 'providers' => [
+ 'Modules\\Author\\Providers\\AuthorServiceProvider',
+ 'Modules\\Author\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [
+ 'AuthorFacade' => 'Modules\\Author\\Facades\\SomeFacade',
+ ],
+ ]);
+
+ $composerJsonPath = $module->subPath('composer.json');
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+
+ /** @var ModuleConfigWriter $configWriter */
+ $configWriter = $this->app->make(ModuleConfigWriter::class);
+ $configWriter->updateAliases($module, [
+ 'foo' => 'Modules\\Author\\Services\\Foo',
+ 'bar' => 'Modules\\Bar\\Services\\Bar',
+ ]);
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+});
+
+it('can add providers via ModuleConfigWriter', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ ]);
+
+ $module = $this->createModule([
+ 'path' => $this->app->basePath('/modules/author'),
+ 'packageName' => 'laraneat/author',
+ 'name' => 'author',
+ 'namespace' => 'Modules\\Author',
+ 'providers' => [
+ 'Modules\\Author\\Providers\\AuthorServiceProvider',
+ 'Modules\\Author\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [
+ 'AuthorFacade' => 'Modules\\Author\\Facades\\SomeFacade',
+ ],
+ ]);
+
+ $composerJsonPath = $module->subPath('composer.json');
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+
+ /** @var ModuleConfigWriter $configWriter */
+ $configWriter = $this->app->make(ModuleConfigWriter::class);
+ $configWriter->addProvider($module, 'Modules\\Author\\Providers\\FooServiceProvider');
+ $configWriter->addProvider($module, 'Modules\\Author\\Providers\\RouteServiceProvider'); // duplicate, should not be added
+ $configWriter->addProvider($module, 'Modules\\Foo\\Providers\\BarServiceProvider');
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+});
+
+it('can add aliases via ModuleConfigWriter', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ ]);
+
+ $module = $this->createModule([
+ 'path' => $this->app->basePath('/modules/author'),
+ 'packageName' => 'laraneat/author',
+ 'name' => 'author',
+ 'namespace' => 'Modules\\Author',
+ 'providers' => [
+ 'Modules\\Author\\Providers\\AuthorServiceProvider',
+ 'Modules\\Author\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [
+ 'AuthorFacade' => 'Modules\\Author\\Facades\\SomeFacade',
+ ],
+ ]);
+
+ $composerJsonPath = $module->subPath('composer.json');
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+
+ /** @var ModuleConfigWriter $configWriter */
+ $configWriter = $this->app->make(ModuleConfigWriter::class);
+ $configWriter->addAlias($module, 'foo', 'Modules\\Author\\Services\\Foo');
+ $configWriter->addAlias($module, 'bar', 'Modules\\Bar\\Services\\Bar');
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+});
diff --git a/tests/ModulesFacadeTest.php b/tests/ModulesFacadeTest.php
deleted file mode 100644
index e9eda09..0000000
--- a/tests/ModulesFacadeTest.php
+++ /dev/null
@@ -1,36 +0,0 @@
-assertIsArray($modules);
- }
-
- /** @test */
- public function it_creates_macros_via_facade()
- {
- $modules = Modules::macro('testMacro', function () {
- return true;
- });
-
- $this->assertTrue(Modules::hasMacro('testMacro'));
- }
-
- /** @test */
- public function it_calls_macros_via_facade()
- {
- $modules = Modules::macro('testMacro', function () {
- return 'a value';
- });
-
- $this->assertEquals('a value', Modules::testMacro());
- }
-}
diff --git a/tests/ModulesRepositoryTest.php b/tests/ModulesRepositoryTest.php
new file mode 100644
index 0000000..85ea62b
--- /dev/null
+++ b/tests/ModulesRepositoryTest.php
@@ -0,0 +1,476 @@
+modulesManifestPath = $this->app->bootstrapPath('cache/testing-laraneat-modules.php');
+ $this->repository = new ModulesRepository(
+ filesystem: $this->app['files'],
+ composer: $this->app[Composer::class],
+ modulesPath: $this->app['config']->get('modules.path'),
+ basePath: $this->app->basePath(),
+ modulesManifestPath: $this->modulesManifestPath,
+ );
+});
+
+afterEach(function () {
+ $this->filesystem->delete($this->modulesManifestPath);
+});
+
+describe('scan paths', function () {
+ it('sets the initial scan paths from the configuration', function () {
+ expect($this->repository->getScanPaths())->toBe([
+ $this->app->basePath('/modules/*'),
+ ]);
+ });
+
+ it('can add one scan path', function () {
+ $this->repository->addScanPath($this->app->basePath('/foo_bar'));
+ expect($this->repository->getScanPaths())->toBe([
+ $this->app->basePath('/modules/*'),
+ $this->app->basePath('/foo_bar/*'),
+ ]);
+ });
+
+ it('can add array of scan paths', function () {
+ $this->repository->addScanPath([
+ $this->app->basePath('/foo/bar/test folder'),
+ $this->app->basePath('/foo/test/'),
+ ]);
+
+ expect($this->repository->getScanPaths())->toBe([
+ $this->app->basePath('/modules/*'),
+ $this->app->basePath('/foo/bar/test folder/*'),
+ $this->app->basePath('/foo/test/*'),
+ ]);
+ });
+
+ it('normalizes the added paths', function () {
+ $this->repository->addScanPath([
+ $this->app->basePath('/foo/bar/some1////'),
+ $this->app->basePath('/foo/bar/some2'),
+ $this->app->basePath('/foo/bar/some3/*'),
+ $this->app->basePath('/foo/bar/some4/*/'),
+ ]);
+
+ expect($this->repository->getScanPaths())->toBe([
+ $this->app->basePath('/modules/*'),
+ $this->app->basePath('/foo/bar/some1/*'),
+ $this->app->basePath('/foo/bar/some2/*'),
+ $this->app->basePath('/foo/bar/some3/*'),
+ $this->app->basePath('/foo/bar/some4/*'),
+ ]);
+ });
+
+ it('rejects adding a path that is already in the scan paths', function () {
+ $this->repository->addScanPath([
+ $this->app->basePath('/modules'),
+ $this->app->basePath('/modules/'),
+ $this->app->basePath('/modules////'),
+ $this->app->basePath('/modules/*'),
+ $this->app->basePath('/modules/Nested'),
+ $this->app->basePath('/modules/Nested/'),
+ $this->app->basePath('/modules/Nested////'),
+ $this->app->basePath('/modules/Nested/*'),
+ $this->app->basePath('/foo/test/'),
+ $this->app->basePath('/foo/test////'),
+ ]);
+
+ expect($this->repository->getScanPaths())->toBe([
+ $this->app->basePath('/modules/*'),
+ $this->app->basePath('/modules/Nested/*'),
+ $this->app->basePath('/foo/test/*'),
+ ]);
+ });
+});
+
+describe('modules manifest', function () {
+ it('can build modules manifest', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ $expectedManifest = [
+ 'laraneat/article-category' => [
+ 'path' => $this->app->basePath('/modules/article-category'),
+ 'name' => 'article-category',
+ 'namespace' => 'Modules\\ArticleCategory\\',
+ 'providers' => [
+ 'Modules\\ArticleCategory\\Providers\\ArticleCategoryServiceProvider',
+ 'Modules\\ArticleCategory\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ],
+ 'laraneat/article' => [
+ 'path' => $this->app->basePath('/modules/article'),
+ 'name' => 'article',
+ 'namespace' => 'Modules\\Article\\',
+ 'providers' => [
+ 'Modules\\Article\\Providers\\ArticleServiceProvider',
+ 'Modules\\Article\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ],
+ 'laraneat/author' => [
+ 'path' => $this->app->basePath('/modules/author'),
+ 'name' => 'author',
+ 'namespace' => 'Modules\\Author\\',
+ 'providers' => [
+ 'Modules\\Author\\Providers\\AuthorServiceProvider',
+ 'Modules\\Author\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [
+ 'AuthorFacade' => 'Modules\\Author\\Facades\\SomeFacade',
+ ],
+ ],
+ 'laraneat/empty' => [
+ 'path' => $this->app->basePath('/modules/empty-module'),
+ 'name' => 'empty-module',
+ 'namespace' => 'Modules\\Empty\\',
+ 'providers' => [],
+ 'aliases' => [],
+ ],
+ 'laraneat/location' => [
+ 'path' => $this->app->basePath('/modules/navigation'),
+ 'name' => 'navigation',
+ 'namespace' => 'Modules\\GeoLocation\\',
+ 'providers' => [
+ 'Modules\\GeoLocation\\Providers\\GeoLocationServiceProvider',
+ 'Modules\\GeoLocation\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ],
+ ];
+
+ expect($this->repository->buildModulesManifest())
+ ->toBe($expectedManifest)
+ ->and($this->modulesManifestPath)->toBeFile();
+ });
+
+ it('throws an exception when modules have the same package names', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-copy',
+ ]);
+
+ $this->repository->buildModulesManifest();
+ })->throws(ModuleHasNonUniquePackageName::class);
+
+ it('can prune modules manifest', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ $this->repository->buildModulesManifest();
+ expect($this->modulesManifestPath)->toBeFile();
+ $this->repository->pruneModulesManifest();
+ expect($this->modulesManifestPath)->not->toBeFile();
+ });
+});
+
+it('can return modules as array', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ expect($this->repository->toArray())->toBe([
+ 'laraneat/article-category' => [
+ 'path' => $this->app->basePath('/modules/article-category'),
+ 'packageName' => 'laraneat/article-category',
+ 'name' => 'article-category',
+ 'namespace' => 'Modules\\ArticleCategory',
+ 'providers' => [
+ 'Modules\\ArticleCategory\\Providers\\ArticleCategoryServiceProvider',
+ 'Modules\\ArticleCategory\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ],
+ 'laraneat/article' => [
+ 'path' => $this->app->basePath('/modules/article'),
+ 'packageName' => 'laraneat/article',
+ 'name' => 'article',
+ 'namespace' => 'Modules\\Article',
+ 'providers' => [
+ 'Modules\\Article\\Providers\\ArticleServiceProvider',
+ 'Modules\\Article\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ],
+ 'laraneat/author' => [
+ 'path' => $this->app->basePath('/modules/author'),
+ 'packageName' => 'laraneat/author',
+ 'name' => 'author',
+ 'namespace' => 'Modules\\Author',
+ 'providers' => [
+ 'Modules\\Author\\Providers\\AuthorServiceProvider',
+ 'Modules\\Author\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [
+ 'AuthorFacade' => 'Modules\\Author\\Facades\\SomeFacade',
+ ],
+ ],
+ 'laraneat/empty' => [
+ 'path' => $this->app->basePath('/modules/empty-module'),
+ 'packageName' => 'laraneat/empty',
+ 'name' => 'empty-module',
+ 'namespace' => 'Modules\\Empty',
+ 'providers' => [],
+ 'aliases' => [],
+ ],
+ 'laraneat/location' => [
+ 'path' => $this->app->basePath('/modules/navigation'),
+ 'packageName' => 'laraneat/location',
+ 'name' => 'navigation',
+ 'namespace' => 'Modules\\GeoLocation',
+ 'providers' => [
+ 'Modules\\GeoLocation\\Providers\\GeoLocationServiceProvider',
+ 'Modules\\GeoLocation\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ],
+ ]);
+});
+
+it('can check the module for existence', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ expect($this->repository->has('laraneat/foo'))->toBe(false)
+ ->and($this->repository->has('laraneat/article'))->toBe(true)
+ ->and($this->repository->has('laraneat/author'))->toBe(true)
+ ->and($this->repository->has('laraneat/location'))->toBe(true)
+ ->and($this->repository->has('laraneat/navigation'))->toBe(false)
+ ->and($this->repository->has('laraneat/book'))->toBe(false)
+ ->and($this->repository->has('laraneat/author/some'))->toBe(false)
+ ->and($this->repository->has('laraneat'))->toBe(false);
+});
+
+it('can count the number of modules', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ expect($this->repository->count())->toBe(5);
+});
+
+it('can find a module', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ expect($this->repository->find('laraneat/article')?->toArray())->toBe([
+ 'path' => $this->app->basePath('/modules/article'),
+ 'packageName' => 'laraneat/article',
+ 'name' => 'article',
+ 'namespace' => 'Modules\\Article',
+ 'providers' => [
+ 'Modules\\Article\\Providers\\ArticleServiceProvider',
+ 'Modules\\Article\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ])
+ ->and($this->repository->find('laraneat')?->toArray())->toBe(null)
+ ->and($this->repository->find('laraneat/article/bar')?->toArray())->toBe(null)
+ ->and($this->repository->find('laraneat/location')?->toArray())->toBe([
+ 'path' => $this->app->basePath('/modules/navigation'),
+ 'packageName' => 'laraneat/location',
+ 'name' => 'navigation',
+ 'namespace' => 'Modules\\GeoLocation',
+ 'providers' => [
+ 'Modules\\GeoLocation\\Providers\\GeoLocationServiceProvider',
+ 'Modules\\GeoLocation\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ])
+ ->and($this->repository->find('laraneat/navigation')?->toArray())->toBe(null)
+ ->and($this->repository->find('laraneat/book')?->toArray())->toBe(null);
+});
+
+it('throws an exception when the module is not found', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ $this->repository->findOrFail('laraneat/book');
+})->throws(ModuleNotFound::class);
+
+it('throws an exception when trying to remove a module that does not exist', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ expect($this->repository->delete('laraneat/book'));
+})->throws(ModuleNotFound::class);
+
+it('can filter modules by name', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ $articleModuleMatch = [
+ 'laraneat/article' => [
+ 'path' => $this->app->basePath('/modules/article'),
+ 'packageName' => 'laraneat/article',
+ 'name' => 'article',
+ 'namespace' => 'Modules\\Article',
+ 'providers' => [
+ 'Modules\\Article\\Providers\\ArticleServiceProvider',
+ 'Modules\\Article\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ],
+ ];
+
+ $locationModuleMatch = [
+ 'laraneat/location' => [
+ 'path' => $this->app->basePath('/modules/navigation'),
+ 'packageName' => 'laraneat/location',
+ 'name' => 'navigation',
+ 'namespace' => 'Modules\\GeoLocation',
+ 'providers' => [
+ 'Modules\\GeoLocation\\Providers\\GeoLocationServiceProvider',
+ 'Modules\\GeoLocation\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ],
+ ];
+
+ expect(collect($this->repository->filterByName('article'))->toArray())->toBe($articleModuleMatch)
+ ->and(collect($this->repository->filterByName('Article'))->toArray())->toBe($articleModuleMatch)
+ ->and(collect($this->repository->filterByName('ARTICLE'))->toArray())->toBe([])
+ ->and(collect($this->repository->filterByName('aarticle'))->toArray())->toBe([])
+ ->and(collect($this->repository->filterByName('location'))->toArray())->toBe($locationModuleMatch)
+ ->and(collect($this->repository->filterByName('navigation'))->toArray())->toBe($locationModuleMatch)
+ ->and(collect($this->repository->filterByName('Navigation'))->toArray())->toBe($locationModuleMatch)
+ ->and(collect($this->repository->filterByName('GeoLocation'))->toArray())->toBe([])
+ ->and(collect($this->repository->filterByName('foo'))->toArray())->toBe([])
+ ->and(collect($this->repository->filterByName('laraneat'))->toArray())->toBe([]);
+
+});
+
+it('throws an exception when modules with the requested name are not found', function () {
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ $articleModuleMatch = [
+ 'laraneat/article' => [
+ 'path' => $this->app->basePath('/modules/article'),
+ 'packageName' => 'laraneat/article',
+ 'name' => 'article',
+ 'namespace' => 'Modules\\Article',
+ 'providers' => [
+ 'Modules\\Article\\Providers\\ArticleServiceProvider',
+ 'Modules\\Article\\Providers\\RouteServiceProvider',
+ ],
+ 'aliases' => [],
+ ],
+ ];
+
+ expect(collect($this->repository->filterByNameOrFail('article'))->toArray())->toBe($articleModuleMatch);
+ expect(fn () => $this->repository->filterByNameOrFail('book'))->toThrow(ModuleNotFound::class);
+});
+
+it('can delete a module', function () {
+ // Set mock BEFORE setModules, because Module instances get Composer from container
+ $this->instance(Composer::class, $this->mockComposer(['removePackages' => true]));
+
+ // Recreate repository with mocked Composer
+ $this->repository = new ModulesRepository(
+ filesystem: $this->app['files'],
+ composer: $this->app[Composer::class],
+ modulesPath: $this->app['config']->get('modules.path'),
+ basePath: $this->app->basePath(),
+ modulesManifestPath: $this->modulesManifestPath,
+ );
+
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ expect($this->repository->has('laraneat/article'))->toBe(true)
+ ->and($this->repository->delete('laraneat/article'))->toBe(true)
+ ->and($this->repository->has('laraneat/article'))->toBe(false);
+});
+
+it('can sync modules with composer', function () {
+ // Set mock BEFORE setModules, because repository uses Composer from container
+ $this->instance(Composer::class, $this->mockComposer(['updatePackages' => true]));
+
+ // Recreate repository with mocked Composer
+ $this->repository = new ModulesRepository(
+ filesystem: $this->app['files'],
+ composer: $this->app[Composer::class],
+ modulesPath: $this->app['config']->get('modules.path'),
+ basePath: $this->app->basePath(),
+ modulesManifestPath: $this->modulesManifestPath,
+ );
+
+ $this->setModules([
+ __DIR__ . '/fixtures/stubs/modules/valid/article',
+ __DIR__ . '/fixtures/stubs/modules/valid/article-category',
+ __DIR__ . '/fixtures/stubs/modules/valid/author',
+ __DIR__ . '/fixtures/stubs/modules/valid/empty-module',
+ __DIR__ . '/fixtures/stubs/modules/valid/navigation',
+ ]);
+
+ $this->backupComposerJson();
+ $composerJsonPath = $this->app->basePath('/composer.json');
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+ $this->repository->syncWithComposer();
+ assertFileExists($composerJsonPath);
+ assertMatchesFileSnapshot($composerJsonPath);
+ $this->resetComposerJson();
+});
diff --git a/tests/ModulesServiceProviderTest.php b/tests/ModulesServiceProviderTest.php
deleted file mode 100644
index cd0f675..0000000
--- a/tests/ModulesServiceProviderTest.php
+++ /dev/null
@@ -1,22 +0,0 @@
-assertInstanceOf(RepositoryInterface::class, app(RepositoryInterface::class));
- $this->assertInstanceOf(RepositoryInterface::class, app('modules'));
- }
-
- /** @test */
- public function it_binds_activator_to_activator_class()
- {
- $this->assertInstanceOf(ActivatorInterface::class, app(ActivatorInterface::class));
- }
-}
diff --git a/tests/NameParserTest.php b/tests/NameParserTest.php
deleted file mode 100644
index 09dc0ec..0000000
--- a/tests/NameParserTest.php
+++ /dev/null
@@ -1,100 +0,0 @@
-getOriginalName());
- }
-
- /** @test */
- public function it_gets_the_table_name()
- {
- $parser = new NameParser('create_users_table');
-
- self::assertEquals('users', $parser->getTableName());
- }
-
- /** @test */
- public function it_gets_the_action_name()
- {
- self::assertEquals('create', (new NameParser('create_users_table'))->getAction());
- self::assertEquals('update', (new NameParser('update_users_table'))->getAction());
- self::assertEquals('delete', (new NameParser('delete_users_table'))->getAction());
- self::assertEquals('remove', (new NameParser('remove_users_table'))->getAction());
- }
-
- /** @test */
- public function it_gets_first_part_of_name_if_no_action_was_guessed()
- {
- self::assertEquals('something', (new NameParser('something_random'))->getAction());
- }
-
- /** @test */
- public function it_gets_the_correct_matched_results()
- {
- $matches = (new NameParser('create_users_table'))->getMatches();
-
- $expected = [
- 'create_users_table',
- 'users',
- ];
-
- self::assertEquals($expected, $matches);
- }
-
- /** @test */
- public function it_gets_the_exploded_parts_of_migration_name()
- {
- $parser = new NameParser('create_users_table');
-
- $expected = [
- 'create',
- 'users',
- 'table',
- ];
-
- self::assertEquals($expected, $parser->getData());
- }
-
- /** @test */
- public function it_can_check_if_current_migration_type_matches_given_type()
- {
- $parser = new NameParser('create_users_table');
-
- self::assertTrue($parser->is('create'));
- }
-
- /** @test */
- public function it_can_check_if_current_migration_is_about_adding()
- {
- self::assertTrue((new NameParser('add_users_table'))->isAdd());
- }
-
- /** @test */
- public function it_can_check_if_current_migration_is_about_deleting()
- {
- self::assertTrue((new NameParser('delete_users_table'))->isDelete());
- }
-
- /** @test */
- public function it_can_check_if_current_migration_is_about_creating()
- {
- self::assertTrue((new NameParser('create_users_table'))->isCreate());
- }
-
- /** @test */
- public function it_makes_a_regex_pattern()
- {
- self::assertEquals('/create_(.*)_table/', (new NameParser('create_users_table'))->getPattern());
- self::assertEquals('/add_(.*)_to_(.*)_table/', (new NameParser('add_column_to_users_table'))->getPattern());
- self::assertEquals('/delete_(.*)_from_(.*)_table/', (new NameParser('delete_users_table'))->getPattern());
- }
-}
diff --git a/tests/Pest.php b/tests/Pest.php
new file mode 100644
index 0000000..8b26e9c
--- /dev/null
+++ b/tests/Pest.php
@@ -0,0 +1,55 @@
+
+ */
+function getRelativeFilePathsInDirectory(string $directory): array
+{
+ $filesystem = new Illuminate\Filesystem\Filesystem();
+
+ return array_map(fn (SplFileInfo $fileInfo) => $fileInfo->getRelativePathname(), $filesystem->allFiles($directory));
+}
+
+/**
+ * @param array $paths
+ * @param string $basePath
+ * @return array
+ */
+function makeAbsolutePaths(array $paths, string $basePath): array
+{
+ $basePath = rtrim($basePath, '\\/');
+
+ return array_map(fn (string $path) => realpath($basePath . '/' . $path), $paths);
+}
+
+function assertsMatchesDirectorySnapshot(string $directory): void
+{
+ expect($directory)->toBeDirectory();
+ $filePaths = getRelativeFilePathsInDirectory($directory);
+ assertMatchesSnapshot($filePaths);
+ foreach (makeAbsolutePaths($filePaths, $directory) as $filePath) {
+ assertMatchesFileSnapshot($filePath);
+ }
+}
+
+uses(Laraneat\Modules\Tests\TestCase::class)
+ ->afterEach(function () {
+ /** @var \Laraneat\Modules\Tests\TestCase $this */
+ $this->pruneModulesPaths();
+ $this->resetComposerJson();
+ })
+ ->in('.');
diff --git a/tests/SchemaParserTest.php b/tests/SchemaParserTest.php
deleted file mode 100644
index 61891fa..0000000
--- a/tests/SchemaParserTest.php
+++ /dev/null
@@ -1,47 +0,0 @@
-string('username');
-\t\t\t\$table->integer('password');\n
-TEXT;
-
- self::assertEquals($expected, $parser->render());
- }
-
- /** @test */
- public function it_generates_migration_methods_for_up_method()
- {
- $parser = new SchemaParser('username:string, password:integer');
-
- $expected = <<string('username');
-\t\t\t\$table->integer('password');\n
-TEXT;
-
- self::assertEquals($expected, $parser->up());
- }
-
- /** @test */
- public function it_generates_migration_methods_for_down_method()
- {
- $parser = new SchemaParser('username:string, password:integer');
-
- $expected = <<dropColumn('username');
-\t\t\t\$table->dropColumn('password');\n
-TEXT;
-
- self::assertEquals($expected, $parser->down());
- }
-}
diff --git a/tests/StubTest.php b/tests/StubTest.php
deleted file mode 100644
index e880c65..0000000
--- a/tests/StubTest.php
+++ /dev/null
@@ -1,84 +0,0 @@
-finder = $this->app['files'];
- }
-
- protected function tearDown(): void
- {
- parent::tearDown();
- $this->finder->delete([
- base_path('my-command.php'),
- base_path('stub-override-exists.php'),
- base_path('stub-override-not-exists.php'),
- ]);
- }
-
- /** @test */
- public function it_initialises_a_stub_instance()
- {
- $stub = new Stub('/model.stub', [
- 'name' => 'Name',
- 'factory' => 'Some\\ModelFactory'
- ]);
-
- $this->assertTrue(Str::contains($stub->getPath(), 'Commands/Generators/stubs/model.stub'));
- $this->assertEquals([
- 'name' => 'Name',
- 'factory' => 'Some\\ModelFactory'
- ], $stub->getReplaces());
- }
-
- /** @test */
- public function it_sets_new_replaces_array()
- {
- $stub = new Stub('/model.stub', [
- 'name' => 'Name',
- ]);
-
- $stub->replace([
- 'factory' => 'Some\\New\\ModelFactory'
- ]);
- $this->assertEquals([
- 'factory' => 'Some\\New\\ModelFactory'
- ], $stub->getReplaces());
- }
-
- /** @test */
- public function it_stores_stub_to_specific_path()
- {
- $stub = new Stub('/command.stub', [
- 'command' => 'my:command',
- 'namespace' => 'Article\\Commands',
- 'class' => 'MyCommand',
- ]);
-
- $stub->saveTo(base_path(), 'my-command.php');
-
- $this->assertTrue($this->finder->exists(base_path('my-command.php')));
- }
-
- /** @test */
- public function it_sets_new_path()
- {
- $stub = new Stub('/model.stub', [
- 'name' => 'Name',
- ]);
-
- $stub->setPath('/new-path/');
-
- $this->assertTrue(Str::contains($stub->getPath(), 'Commands/Generators/stubs/new-path/'));
- }
-}
diff --git a/tests/Support/Generator/GeneratorHelperTest.php b/tests/Support/Generator/GeneratorHelperTest.php
new file mode 100644
index 0000000..e9bda89
--- /dev/null
+++ b/tests/Support/Generator/GeneratorHelperTest.php
@@ -0,0 +1,134 @@
+toBe('src/some/Actions');
+ expect(GeneratorHelper::normalizePath('/src/some/Actions'))->toBe('src/some/Actions');
+ expect(GeneratorHelper::normalizePath('/src/some\\Actions/'))->toBe('src/some/Actions');
+ expect(GeneratorHelper::normalizePath('/src/some/Actions///'))->toBe('src/some/Actions');
+ expect(GeneratorHelper::normalizePath('////src/some/Actions\\'))->toBe('src/some/Actions');
+ expect(GeneratorHelper::normalizePath('////src\\some/Actions////'))->toBe('src/some/Actions');
+ expect(GeneratorHelper::normalizePath('\\src\\some\\Actions'))->toBe('src/some/Actions');
+ expect(GeneratorHelper::normalizePath('\\\\src\\some\\Actions\\\\'))->toBe('src/some/Actions');
+ });
+
+ it('correctly normalizes path using rtrim', function () {
+ expect(GeneratorHelper::normalizePath('src/some/Actions', true))->toBe('src/some/Actions');
+ expect(GeneratorHelper::normalizePath('/src/some/Actions', true))->toBe('/src/some/Actions');
+ expect(GeneratorHelper::normalizePath('/src/some\\Actions/', true))->toBe('/src/some/Actions');
+ expect(GeneratorHelper::normalizePath('/src/some/Actions///', true))->toBe('/src/some/Actions');
+ expect(GeneratorHelper::normalizePath('////src/some/Actions\\', true))->toBe('/src/some/Actions');
+ expect(GeneratorHelper::normalizePath('////src\\some/Actions////', true))->toBe('/src/some/Actions');
+ expect(GeneratorHelper::normalizePath('\\src\\some\\Actions', true))->toBe('/src/some/Actions');
+ expect(GeneratorHelper::normalizePath('\\\\src\\some\\Actions\\\\', true))->toBe('/src/some/Actions');
+ });
+});
+
+describe('normalizeNamespace()', function () {
+ it('correctly normalizes namespace', function () {
+ expect(GeneratorHelper::normalizeNamespace('src/some/Actions'))->toBe('src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('/src/some/Actions'))->toBe('src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('/src/some\\Actions/'))->toBe('src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('/src/some/Actions///'))->toBe('src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('////src/some/Actions\\'))->toBe('src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('////src\\some/Actions////'))->toBe('src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('\\src\\some\\Actions'))->toBe('src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('\\\\src\\some\\Actions\\\\'))->toBe('src\\some\\Actions');
+ });
+
+ it('correctly normalizes namespace using rtrim', function () {
+ expect(GeneratorHelper::normalizeNamespace('src/some/Actions', true))->toBe('src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('/src/some/Actions', true))->toBe('\\src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('/src/some\\Actions/', true))->toBe('\\src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('/src/some/Actions///', true))->toBe('\\src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('////src/some/Actions\\', true))->toBe('\\src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('////src\\some/Actions////', true))->toBe('\\src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('\\src\\some\\Actions', true))->toBe('\\src\\some\\Actions');
+ expect(GeneratorHelper::normalizeNamespace('\\\\src\\some\\Actions\\\\', true))->toBe('\\src\\some\\Actions');
+ });
+});
+
+describe('makeRelativePath()', function () {
+ it('correctly make relative', function () {
+ expect(GeneratorHelper::makeRelativePath('', ''))->toBe('');
+ expect(GeneratorHelper::makeRelativePath('/', ''))->toBe(null);
+ expect(GeneratorHelper::makeRelativePath('', '/'))->toBe(null);
+ expect(GeneratorHelper::makeRelativePath('src/some/foo/bar', 'src/some/foo/bar'))->toBe('');
+ expect(GeneratorHelper::makeRelativePath('/src/some/foo/bar', 'src/some/foo/bar'))->toBe(null);
+ expect(GeneratorHelper::makeRelativePath('src/some/foo/bar', '/src/some/foo/bar'))->toBe(null);
+ expect(GeneratorHelper::makeRelativePath('src/some/foo/bar', 'src/some'))->toBe('../..');
+ expect(GeneratorHelper::makeRelativePath('src/some', 'src/some/foo/bar'))->toBe('foo/bar');
+ expect(GeneratorHelper::makeRelativePath('/src/some', '/src/some/foo/bar'))->toBe('foo/bar');
+ expect(GeneratorHelper::makeRelativePath('src/some/bar', 'src/some/foo/bar'))->toBe('../foo/bar');
+ expect(GeneratorHelper::makeRelativePath('src/some/foo/bar', 'src/some/bar'))->toBe('../../bar');
+ expect(GeneratorHelper::makeRelativePath('src/some/bar/baz', 'src/some/foo/bar/baz'))->toBe('../../foo/bar/baz');
+ expect(GeneratorHelper::makeRelativePath('src/some/foo/bar/baz', 'src/some/bar/baz'))->toBe('../../../bar/baz');
+ expect(GeneratorHelper::makeRelativePath('/src/some/foo/bar/baz', '/src/some/bar/baz'))->toBe('../../../bar/baz');
+ expect(GeneratorHelper::makeRelativePath('/src/some/foo/bar/baz', '////src/some/bar/baz'))->toBe('../../../bar/baz');
+ expect(GeneratorHelper::makeRelativePath('/////src/some/foo/bar/baz', '/src/some/bar/baz'))->toBe('../../../bar/baz');
+ expect(GeneratorHelper::makeRelativePath('foo/bar/baz', 'src/some/bar/baz'))->toBe(null);
+ });
+});
+
+describe('getBasePath()', function () {
+ it('returns base path', function () {
+ $this->app['config']->set('modules.path', $this->app->basePath('/foo/bar'));
+
+ expect(GeneratorHelper::getBasePath())->toBe($this->app->basePath('/foo/bar'));
+
+ $this->app['config']->set('modules.path', $this->app->basePath('/foo/bar/') . '///');
+
+ expect(GeneratorHelper::getBasePath())->toBe($this->app->basePath('/foo/bar'));
+ });
+
+ it('throws an error when the modules path is not defined', function () {
+ $this->app['config']->set('modules.path', '');
+
+ expect(fn () => GeneratorHelper::getBasePath())->toThrow(InvalidConfigValue::class);
+ });
+});
+
+describe('getBaseNamespace()', function () {
+ it('returns base namespace', function () {
+ $this->app['config']->set('modules.namespace', '\\Foo\\Bar\\');
+
+ expect(GeneratorHelper::getBaseNamespace())->toBe('Foo\\Bar');
+ });
+
+ it('throws an error when the modules namespace is not defined', function () {
+ $this->app['config']->set('modules.namespace', '');
+
+ expect(fn () => GeneratorHelper::getBaseNamespace())->toThrow(InvalidConfigValue::class);
+ });
+});
+
+describe('component(ModuleComponentType $componentType)', function () {
+ it('returns component config by type', function () {
+ $this->app['config']->set('modules.components.' . ModuleComponentType::Action->value, [
+ 'path' => '///Some/Actions///',
+ ]);
+
+ expect(GeneratorHelper::component(ModuleComponentType::Action)->getPath())->toBe('Some/Actions');
+ expect(GeneratorHelper::component(ModuleComponentType::Action)->getNamespace())->toBe('Some\\Actions');
+
+ $this->app['config']->set('modules.components.' . ModuleComponentType::Action->value, [
+ 'path' => '///src/Some/Actions///',
+ 'namespace' => '\\\\\\Some\\Actions\\\\\\',
+ ]);
+
+ expect(GeneratorHelper::component(ModuleComponentType::Action)->getPath())->toBe('src/Some/Actions');
+ expect(GeneratorHelper::component(ModuleComponentType::Action)->getNamespace())->toBe('Some\\Actions');
+ });
+
+ it('throws an error when the component has invalid config', function () {
+ $this->app['config']->set('modules.components.' . ModuleComponentType::Action->value, 'foo');
+ expect(fn () => GeneratorHelper::component(ModuleComponentType::Action))->toThrow(InvalidConfigValue::class);
+
+ $this->app['config']->set('modules.components.' . ModuleComponentType::Action->value, ['namespace' => 'Some\\Actions']);
+ expect(fn () => GeneratorHelper::component(ModuleComponentType::Action))->toThrow(InvalidConfigValue::class);
+ });
+});
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..814ae6e
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,208 @@
+resolveDefaultApplication();
+ }
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->filesystem = $this->app['files'];
+ }
+
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+
+ Mockery::close();
+ }
+
+ protected function getPackageProviders($app): array
+ {
+ return [
+ ComposerServiceProvider::class,
+ ConsoleServiceProvider::class,
+ ModulesRepositoryServiceProvider::class,
+ ModulesServiceProvider::class,
+ ];
+ }
+
+ protected function getPackageAliases($app): array
+ {
+ return [
+ 'Modules' => Modules::class,
+ ];
+ }
+
+ /**
+ * @param Application $app
+ */
+ protected function getEnvironmentSetUp($app): void
+ {
+ $app['config']->set('database.default', 'sqlite');
+ $app['config']->set('database.connections.sqlite', [
+ 'driver' => 'sqlite',
+ 'database' => ':memory:',
+ 'prefix' => '',
+ ]);
+ }
+
+ /**
+ * @param string[] $paths
+ */
+ public function setModules(array $paths, ?string $modulesPath = null): void
+ {
+ $modulesPath = rtrim($modulesPath ?? GeneratorHelper::getBasePath(), '/');
+ $this->addModulesPath($modulesPath);
+ $this->filesystem->ensureDirectoryExists($modulesPath);
+
+ foreach ($paths as $modulePath) {
+ $modulePath = rtrim($modulePath, '/');
+ $this->filesystem->copyDirectory($modulePath, $modulesPath . '/' . Str::afterLast($modulePath, '/'));
+ }
+
+ $this->app[ModulesRepository::class]->pruneModulesManifest();
+ }
+
+ public function pruneModulesPaths(): void
+ {
+ if ($this->modulesPaths) {
+ foreach ($this->modulesPaths as $path) {
+ if ($this->filesystem->isDirectory($path)) {
+ $this->filesystem->deleteDirectory($path);
+ }
+ }
+ $this->modulesPaths = [];
+ $this->app[ModulesRepository::class]->pruneModulesManifest();
+ }
+ }
+
+ public function backupComposerJson(): void
+ {
+ if ($this->composerJsonBackupPath !== null) {
+ return;
+ }
+
+ $this->composerJsonBackupPath = $this->app->basePath('/composer.backup.json');
+ if ($this->filesystem->isFile($this->composerJsonBackupPath)) {
+ $this->resetComposerJson();
+ $this->composerJsonBackupPath = $this->app->basePath('/composer.backup.json');
+ }
+ $this->filesystem->copy($this->app->basePath('/composer.json'), $this->composerJsonBackupPath);
+ }
+
+ public function resetComposerJson(): void
+ {
+ if ($this->composerJsonBackupPath === null) {
+ return;
+ }
+
+ if ($this->filesystem->isFile($this->composerJsonBackupPath)) {
+ $this->filesystem->delete($this->app->basePath('/composer.json'));
+ $this->filesystem->copy($this->composerJsonBackupPath, $this->app->basePath('/composer.json'));
+ $this->filesystem->delete($this->composerJsonBackupPath);
+ }
+ $this->composerJsonBackupPath = null;
+ }
+
+ /**
+ * @param array $attributes
+ */
+ public function createModule(array $attributes = []): Module
+ {
+ return new Module(
+ packageName: $attributes['packageName'] ?? 'some-vendor/testing-module',
+ name: $attributes['name'] ?? '',
+ path: $attributes['path'] ?? $this->app->basePath('modules/TestingModule'),
+ namespace: $attributes['namespace'] ?? 'SomeVendor\\TestingModule\\',
+ providers: $attributes['providers'] ?? [
+ 'SomeVendor\\TestingModule\\Providers\\TestingModuleServiceProvider',
+ 'SomeVendor\\TestingModule\\Providers\\RouteServiceProvider',
+ ],
+ aliases: $attributes['aliases'] ?? [
+ 'testing-module' => 'SomeVendor\\TestingModule\\Facades\\TestingModule',
+ ],
+ );
+ }
+
+ /**
+ * Create a mock of Composer class for testing.
+ *
+ * @param array $methodExpectations Array of method names to their expected return values
+ *
+ * @return MockInterface&Composer
+ */
+ public function mockComposer(array $methodExpectations = []): MockInterface
+ {
+ $composer = Mockery::mock(Composer::class);
+
+ foreach ($methodExpectations as $method => $returnValue) {
+ $composer->shouldReceive($method)->andReturn($returnValue);
+ }
+
+ return $composer;
+ }
+
+ private function addModulesPath(string $path): void
+ {
+ if (in_array($path, $this->modulesPaths, true)) {
+ return;
+ }
+
+ if ($this->filesystem->isDirectory($path)) {
+ $this->filesystem->deleteDirectories($path);
+ }
+
+ $this->modulesPaths[] = $path;
+ }
+}
diff --git a/tests/__snapshots__/ModuleMakeCommandTest__it_generates_a__api__module__2.yml b/tests/__snapshots__/ModuleMakeCommandTest__it_generates_a__api__module__2.yml
new file mode 100644
index 0000000..386aaae
--- /dev/null
+++ b/tests/__snapshots__/ModuleMakeCommandTest__it_generates_a__api__module__2.yml
@@ -0,0 +1,33 @@
+- composer.json
+- database/factories/ArticleCommentFactory.php
+- database/migrations/2024_01_01_000000_create_article_comments_table.php
+- database/seeders/ArticleCommentPermissionsSeeder_1.php
+- src/Actions/CreateArticleCommentAction.php
+- src/Actions/DeleteArticleCommentAction.php
+- src/Actions/ListArticleCommentsAction.php
+- src/Actions/UpdateArticleCommentAction.php
+- src/Actions/ViewArticleCommentAction.php
+- src/DTO/CreateArticleCommentDTO.php
+- src/DTO/UpdateArticleCommentDTO.php
+- src/Models/ArticleComment.php
+- src/Policies/ArticleCommentPolicy.php
+- src/Providers/ArticleCommentServiceProvider.php
+- src/Providers/RouteServiceProvider.php
+- src/UI/API/QueryWizards/ArticleCommentQueryWizard.php
+- src/UI/API/QueryWizards/ArticleCommentsQueryWizard.php
+- src/UI/API/Requests/CreateArticleCommentRequest.php
+- src/UI/API/Requests/DeleteArticleCommentRequest.php
+- src/UI/API/Requests/ListArticleCommentsRequest.php
+- src/UI/API/Requests/UpdateArticleCommentRequest.php
+- src/UI/API/Requests/ViewArticleCommentRequest.php
+- src/UI/API/Resources/ArticleCommentResource.php
+- src/UI/API/routes/v1/create_article_comment.php
+- src/UI/API/routes/v1/delete_article_comment.php
+- src/UI/API/routes/v1/list_article_comments.php
+- src/UI/API/routes/v1/update_article_comment.php
+- src/UI/API/routes/v1/view_article_comment.php
+- tests/UI/API/CreateArticleCommentTest.php
+- tests/UI/API/DeleteArticleCommentTest.php
+- tests/UI/API/ListArticleCommentsTest.php
+- tests/UI/API/UpdateArticleCommentTest.php
+- tests/UI/API/ViewArticleCommentTest.php
diff --git a/tests/__snapshots__/ModuleMakeCommandTest__it_generates_a__base__module__2.yml b/tests/__snapshots__/ModuleMakeCommandTest__it_generates_a__base__module__2.yml
new file mode 100644
index 0000000..d03888b
--- /dev/null
+++ b/tests/__snapshots__/ModuleMakeCommandTest__it_generates_a__base__module__2.yml
@@ -0,0 +1,8 @@
+- composer.json
+- database/factories/ArticleCommentFactory.php
+- database/migrations/2024_01_01_000000_create_article_comments_table.php
+- database/seeders/ArticleCommentPermissionsSeeder_1.php
+- src/Models/ArticleComment.php
+- src/Policies/ArticleCommentPolicy.php
+- src/Providers/ArticleCommentServiceProvider.php
+- src/Providers/RouteServiceProvider.php
diff --git a/tests/__snapshots__/ModuleMakeCommandTest__it_generates_a__plain__module__2.yml b/tests/__snapshots__/ModuleMakeCommandTest__it_generates_a__plain__module__2.yml
new file mode 100644
index 0000000..173b667
--- /dev/null
+++ b/tests/__snapshots__/ModuleMakeCommandTest__it_generates_a__plain__module__2.yml
@@ -0,0 +1,3 @@
+- composer.json
+- src/Providers/ArticleCommentServiceProvider.php
+- src/Providers/RouteServiceProvider.php
diff --git a/tests/__snapshots__/StubPublishCommandTest__it_publish_all_laraneat_modules_stubs__1.yml b/tests/__snapshots__/StubPublishCommandTest__it_publish_all_laraneat_modules_stubs__1.yml
new file mode 100644
index 0000000..2d90c51
--- /dev/null
+++ b/tests/__snapshots__/StubPublishCommandTest__it_publish_all_laraneat_modules_stubs__1.yml
@@ -0,0 +1,63 @@
+- action/create.stub
+- action/delete.stub
+- action/list.stub
+- action/plain.stub
+- action/update.stub
+- action/view.stub
+- command.stub
+- composer.json.stub
+- controller/api.stub
+- controller/web.stub
+- dto.stub
+- event.stub
+- exception.stub
+- factory.stub
+- job/plain.stub
+- job/queued.stub
+- listener/plain.stub
+- listener/queued.stub
+- mail.stub
+- middleware.stub
+- migration/add.stub
+- migration/create.stub
+- migration/delete.stub
+- migration/pivot.stub
+- migration/plain.stub
+- model/full.stub
+- model/plain.stub
+- notification/plain.stub
+- notification/queued.stub
+- observer.stub
+- policy/full.stub
+- policy/plain.stub
+- provider/event.stub
+- provider/module.stub
+- provider/plain.stub
+- provider/route.stub
+- query-wizard/eloquent.stub
+- query-wizard/model.stub
+- request/create.stub
+- request/delete.stub
+- request/list.stub
+- request/plain.stub
+- request/update.stub
+- request/view.stub
+- resource/collection.stub
+- resource/single.stub
+- route.stub
+- rule.stub
+- seeder/permissions.stub
+- seeder/plain.stub
+- test/api/create.stub
+- test/api/delete.stub
+- test/api/list.stub
+- test/api/plain.stub
+- test/api/update.stub
+- test/api/view.stub
+- test/cli/plain.stub
+- test/feature/plain.stub
+- test/unit/plain.stub
+- test/web/create.stub
+- test/web/delete.stub
+- test/web/plain.stub
+- test/web/update.stub
diff --git a/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__create__action_for_the_module__1.php b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__create__action_for_the_module__1.php
new file mode 100644
index 0000000..ed01161
--- /dev/null
+++ b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__create__action_for_the_module__1.php
@@ -0,0 +1,27 @@
+all());
+ }
+
+ public function asController(CreateAuthorRequest $request): JsonResponse
+ {
+ $author = $this->handle($request->toDTO());
+
+ return (new AuthorResource($author))->created();
+ }
+}
diff --git a/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__delete__action_for_the_module__1.php b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__delete__action_for_the_module__1.php
new file mode 100644
index 0000000..0f8b701
--- /dev/null
+++ b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__delete__action_for_the_module__1.php
@@ -0,0 +1,25 @@
+delete();
+ }
+
+ public function asController(DeleteAuthorRequest $request, Author $author): Response
+ {
+ $this->handle($author);
+
+ return $this->noContent();
+ }
+}
diff --git a/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__list__action_for_the_module__1.php b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__list__action_for_the_module__1.php
new file mode 100644
index 0000000..1a51d18
--- /dev/null
+++ b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__list__action_for_the_module__1.php
@@ -0,0 +1,28 @@
+build()
+ ->paginate();
+ }
+
+ public function asController(ListAuthorsRequest $request): AnonymousResourceCollection
+ {
+ return AuthorResource::collection($this->handle($request));
+ }
+}
diff --git a/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__plain__action_for_the_module__1.php b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__plain__action_for_the_module__1.php
new file mode 100644
index 0000000..148c7ab
--- /dev/null
+++ b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__plain__action_for_the_module__1.php
@@ -0,0 +1,15 @@
+all();
+
+ if ($data) {
+ $author->update($data);
+ }
+
+ return $author;
+ }
+
+ public function asController(UpdateAuthorRequest $request, Author $author): AuthorResource
+ {
+ $author = $this->handle($author, $request->toDTO());
+
+ return new AuthorResource($author);
+ }
+}
diff --git a/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__view__action_for_the_module__1.php b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__view__action_for_the_module__1.php
new file mode 100644
index 0000000..3443c4b
--- /dev/null
+++ b/tests/__snapshots__/files/ActionMakeCommandTest__it_generates__view__action_for_the_module__1.php
@@ -0,0 +1,25 @@
+build();
+ }
+
+ public function asController(ViewAuthorRequest $request, Author $author): AuthorResource
+ {
+ return new AuthorResource($this->handle($request, $author));
+ }
+}
diff --git a/tests/__snapshots__/files/CommandMakeCommandTest__it_generates_console_command_for_the_module__1.php b/tests/__snapshots__/files/CommandMakeCommandTest__it_generates_console_command_for_the_module__1.php
new file mode 100644
index 0000000..0f87a39
--- /dev/null
+++ b/tests/__snapshots__/files/CommandMakeCommandTest__it_generates_console_command_for_the_module__1.php
@@ -0,0 +1,30 @@
+|Author create($attributes = [], ?Author $parent = null)
+ * @method \Illuminate\Support\Collection createMany(iterable $records)
+ * @method Author createOne($attributes = [])
+ * @method \Illuminate\Support\Collection|Author make($attributes = [], ?Author $parent = null)
+ * @method Author makeOne($attributes = [])
+ */
+class SomeAuthorFactory extends Factory
+{
+ /**
+ * The name of the factory's corresponding model.
+ *
+ * @var class-string
+ */
+ protected $model = Author::class;
+
+ /**
+ * Define the model's default state.
+ */
+ public function definition(): array
+ {
+ return [
+ // TODO: add fields here
+ ];
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/JobMakeCommandTest__it_generated_correct_plain_job_file_with_content__1.txt b/tests/__snapshots__/files/JobMakeCommandTest__it_generates__plain__job_for_the_module__1.php
similarity index 67%
rename from tests/Commands/Generators/__snapshots__/JobMakeCommandTest__it_generated_correct_plain_job_file_with_content__1.txt
rename to tests/__snapshots__/files/JobMakeCommandTest__it_generates__plain__job_for_the_module__1.php
index 552312c..eb911c8 100644
--- a/tests/Commands/Generators/__snapshots__/JobMakeCommandTest__it_generated_correct_plain_job_file_with_content__1.txt
+++ b/tests/__snapshots__/files/JobMakeCommandTest__it_generates__plain__job_for_the_module__1.php
@@ -1,14 +1,16 @@
+ */
+ public function attachments(): array
+ {
+ return [];
+ }
+}
diff --git a/tests/__snapshots__/files/MiddlewareMakeCommandTest__it_generates_middleware_for_the_module__1.php b/tests/__snapshots__/files/MiddlewareMakeCommandTest__it_generates_middleware_for_the_module__1.php
new file mode 100644
index 0000000..d2f58c3
--- /dev/null
+++ b/tests/__snapshots__/files/MiddlewareMakeCommandTest__it_generates_middleware_for_the_module__1.php
@@ -0,0 +1,20 @@
+dropColumn('title');
+ Schema::table('articles', static function (Blueprint $table) {
+ $table->string('title');
});
}
@@ -22,8 +22,8 @@ public function up(): void
*/
public function down(): void
{
- Schema::table('posts', static function (Blueprint $table) {
- $table->string('title');
+ Schema::table('articles', static function (Blueprint $table) {
+ $table->dropColumn('title');
});
}
diff --git a/tests/Commands/Generators/__snapshots__/MigrationMakeCommandTest__it_generates_correct_create_migration_file_content__1.txt b/tests/__snapshots__/files/MigrationMakeCommandTest__it_automatically_detects_and_generates__create__migration_for_the_module__1.php
similarity index 84%
rename from tests/Commands/Generators/__snapshots__/MigrationMakeCommandTest__it_generates_correct_create_migration_file_content__1.txt
rename to tests/__snapshots__/files/MigrationMakeCommandTest__it_automatically_detects_and_generates__create__migration_for_the_module__1.php
index 09bf48b..a1fea11 100644
--- a/tests/Commands/Generators/__snapshots__/MigrationMakeCommandTest__it_generates_correct_create_migration_file_content__1.txt
+++ b/tests/__snapshots__/files/MigrationMakeCommandTest__it_automatically_detects_and_generates__create__migration_for_the_module__1.php
@@ -11,7 +11,7 @@
*/
public function up(): void
{
- Schema::create('posts', static function (Blueprint $table) {
+ Schema::create('articles', static function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('excerpt');
@@ -28,6 +28,6 @@ public function up(): void
*/
public function down(): void
{
- Schema::dropIfExists('posts');
+ Schema::dropIfExists('articles');
}
};
diff --git a/tests/Commands/Generators/__snapshots__/MigrationMakeCommandTest__it_generates_correct_add_migration_file_content__1.txt b/tests/__snapshots__/files/MigrationMakeCommandTest__it_automatically_detects_and_generates__delete__migration_for_the_module__1.php
similarity index 75%
rename from tests/Commands/Generators/__snapshots__/MigrationMakeCommandTest__it_generates_correct_add_migration_file_content__1.txt
rename to tests/__snapshots__/files/MigrationMakeCommandTest__it_automatically_detects_and_generates__delete__migration_for_the_module__1.php
index 48da517..02dbdeb 100644
--- a/tests/Commands/Generators/__snapshots__/MigrationMakeCommandTest__it_generates_correct_add_migration_file_content__1.txt
+++ b/tests/__snapshots__/files/MigrationMakeCommandTest__it_automatically_detects_and_generates__delete__migration_for_the_module__1.php
@@ -11,8 +11,8 @@
*/
public function up(): void
{
- Schema::table('posts', static function (Blueprint $table) {
- $table->string('title');
+ Schema::table('articles', static function (Blueprint $table) {
+ $table->dropColumn('title');
});
}
@@ -22,8 +22,8 @@ public function up(): void
*/
public function down(): void
{
- Schema::table('posts', static function (Blueprint $table) {
- $table->dropColumn('title');
+ Schema::table('articles', static function (Blueprint $table) {
+ $table->string('title');
});
}
diff --git a/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__add__migration_for_the_module__1.php b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__add__migration_for_the_module__1.php
new file mode 100644
index 0000000..34f727a
--- /dev/null
+++ b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__add__migration_for_the_module__1.php
@@ -0,0 +1,36 @@
+string('title');
+ $table->text('excerpt');
+ $table->integer('user_id')->unsigned();
+ $table->foreign('user_id')->references('id')->on('users');
+
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('articles', static function (Blueprint $table) {
+ $table->dropColumn('title');
+ $table->dropColumn('excerpt');
+ $table->dropColumn('user_id');
+ $table->dropForeign(['user_id']);
+
+ });
+ }
+};
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__65.txt b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__add__migration_for_the_module_without_fields__1.php
similarity index 68%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__65.txt
rename to tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__add__migration_for_the_module_without_fields__1.php
index f39c303..11a9d71 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__65.txt
+++ b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__add__migration_for_the_module_without_fields__1.php
@@ -11,10 +11,8 @@
*/
public function up(): void
{
- Schema::create('posts', static function (Blueprint $table) {
- $table->id();
+ Schema::table('articles', static function (Blueprint $table) {
- $table->timestamps();
});
}
@@ -23,6 +21,8 @@ public function up(): void
*/
public function down(): void
{
- Schema::dropIfExists('posts');
+ Schema::table('articles', static function (Blueprint $table) {
+
+ });
}
};
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__31.txt b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__create__migration_for_the_module__1.php
similarity index 74%
rename from tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__31.txt
rename to tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__create__migration_for_the_module__1.php
index 13b5e38..a1fea11 100644
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__31.txt
+++ b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__create__migration_for_the_module__1.php
@@ -13,6 +13,11 @@ public function up(): void
{
Schema::create('articles', static function (Blueprint $table) {
$table->id();
+ $table->string('title');
+ $table->text('excerpt');
+ $table->text('content');
+ $table->integer('user_id')->unsigned();
+ $table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__31.txt b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__create__migration_for_the_module_without_fields__1.php
similarity index 100%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__31.txt
rename to tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__create__migration_for_the_module_without_fields__1.php
diff --git a/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__delete__migration_for_the_module__1.php b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__delete__migration_for_the_module__1.php
new file mode 100644
index 0000000..72d9761
--- /dev/null
+++ b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__delete__migration_for_the_module__1.php
@@ -0,0 +1,36 @@
+dropColumn('title');
+ $table->dropColumn('excerpt');
+ $table->dropColumn('user_id');
+ $table->dropForeign(['user_id']);
+
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('articles', static function (Blueprint $table) {
+ $table->string('title');
+ $table->text('excerpt');
+ $table->integer('user_id')->unsigned();
+ $table->foreign('user_id')->references('id')->on('users');
+
+ });
+ }
+};
diff --git a/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__delete__migration_for_the_module_without_fields__1.php b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__delete__migration_for_the_module_without_fields__1.php
new file mode 100644
index 0000000..11a9d71
--- /dev/null
+++ b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__delete__migration_for_the_module_without_fields__1.php
@@ -0,0 +1,28 @@
+unsignedBigInteger('article_id')->index();
+ $table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');
+ $table->unsignedBigInteger('author_id')->index();
+ $table->foreign('author_id')->references('id')->on('authors')->onDelete('cascade');
+ $table->primary(['article_id', 'author_id']);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('article_author');
+ }
+};
diff --git a/tests/Commands/Generators/__snapshots__/MigrationMakeCommandTest__it_generates_correct_plain_migration_file_content__1.txt b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__plain__migration_for_the_module__1.php
similarity index 100%
rename from tests/Commands/Generators/__snapshots__/MigrationMakeCommandTest__it_generates_correct_plain_migration_file_content__1.txt
rename to tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__plain__migration_for_the_module__1.php
diff --git a/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__plain__migration_for_the_module_if_the_stub_is_not_recognized_by_name__1.php b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__plain__migration_for_the_module_if_the_stub_is_not_recognized_by_name__1.php
new file mode 100644
index 0000000..88fa2f3
--- /dev/null
+++ b/tests/__snapshots__/files/MigrationMakeCommandTest__it_generates__plain__migration_for_the_module_if_the_stub_is_not_recognized_by_name__1.php
@@ -0,0 +1,24 @@
+all();
+
+ if ($data) {
+ $articleComment->update($data);
+ }
+
+ return $articleComment;
+ }
+
+ public function asController(UpdateArticleCommentRequest $request, ArticleComment $articleComment): ArticleCommentResource
+ {
+ $articleComment = $this->handle($articleComment, $request->toDTO());
+
+ return new ArticleCommentResource($articleComment);
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__11.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__11.php
new file mode 100644
index 0000000..74f5661
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__11.php
@@ -0,0 +1,25 @@
+build();
+ }
+
+ public function asController(ViewArticleCommentRequest $request, ArticleComment $articleComment): ArticleCommentResource
+ {
+ return new ArticleCommentResource($this->handle($request, $articleComment));
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__12.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__12.php
new file mode 100644
index 0000000..3bbcd57
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__12.php
@@ -0,0 +1,13 @@
+can('view-article-comment');
+ }
+
+ /**
+ * Determine whether the user can view the model.
+ */
+ public function view(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('view-article-comment');
+ }
+
+ /**
+ * Determine whether the user can create models.
+ */
+ public function create(User $user): bool
+ {
+ return $user->can('create-article-comment');
+ }
+
+ /**
+ * Determine whether the user can update the model.
+ */
+ public function update(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('update-article-comment');
+ }
+
+ /**
+ * Determine whether the user can delete the model.
+ */
+ public function delete(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('delete-article-comment');
+ }
+
+ /**
+ * Determine whether the user can restore the model.
+ */
+ public function restore(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('delete-article-comment');
+ }
+
+ /**
+ * Determine whether the user can permanently delete the model.
+ */
+ public function forceDelete(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('force-delete-article-comment');
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__16.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__16.php
new file mode 100644
index 0000000..1696363
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__16.php
@@ -0,0 +1,102 @@
+loadConfigurations();
+ }
+
+ /**
+ * Bootstrap services.
+ */
+ public function boot(): void
+ {
+ $this->loadMigrations();
+ // $this->loadCommands();
+ // $this->loadTranslations();
+ // $this->loadViews();
+ }
+
+ /**
+ * Register configuration files.
+ */
+ public function loadConfigurations(): void
+ {
+ $sourcePath = __DIR__.'/../../config/article-comment.php';
+ $configsPath = $this->app->configPath('article-comment.php');
+
+ $this->mergeConfigFrom($sourcePath, 'article-comment');
+
+ $this->publishes([
+ $sourcePath => $configsPath
+ ], 'article-comment-config');
+ }
+
+ /**
+ * Register migrations.
+ */
+ public function loadMigrations(): void
+ {
+ $sourcePath = __DIR__.'/../../database/migrations';
+ $migrationsPath = $this->app->databasePath('migrations');
+
+ $this->loadMigrationsFrom($sourcePath);
+
+ $this->publishes([
+ $sourcePath => $migrationsPath
+ ], 'article-comment-migrations');
+ }
+
+ /**
+ * Register artisan commands.
+ */
+ public function loadCommands(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ 'Modules\\ArticleComment\\UI\\CLI\\Commands' => __DIR__.'/../UI/CLI/Commands',
+ ]);
+ }
+ }
+
+ /**
+ * Register translations.
+ */
+ public function loadTranslations(): void
+ {
+ $sourcePath = __DIR__.'/../../lang';
+ $langPath = $this->app->langPath('modules/article-comment');
+
+ $this->loadTranslationsFrom($sourcePath, 'article-comment');
+
+ $this->publishes([
+ $sourcePath => $langPath,
+ ], 'article-comment-translations');
+ }
+
+ /**
+ * Register views.
+ */
+ public function loadViews(): void
+ {
+ $sourcePath = __DIR__.'/../../resources/views';
+ $viewsPath = $this->app->resourcePath('views/modules/article-comment');
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths('article-comment'), [$sourcePath]),
+ 'article-comment'
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath
+ ], 'article-comment-views');
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__44.txt b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__17.php
similarity index 63%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__44.txt
rename to tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__17.php
index 3d39542..ba84e41 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__44.txt
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__17.php
@@ -1,16 +1,14 @@
namespace('App\\Modules\\Blog\\UI\\WEB\\Controllers')
+ // ->namespace('Modules\\ArticleComment\\UI\\WEB\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/WEB/Routes'));
+ $this->loadRoutesFromDirectory(__DIR__.'/../UI/WEB/routes');
});
}
@@ -51,9 +49,9 @@ protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
-// ->namespace('App\\Modules\\Blog\\UI\\API\\Controllers')
+ // ->namespace('Modules\\ArticleComment\\UI\\API\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/API/Routes'));
+ $this->loadRoutesFromDirectory(__DIR__.'/../UI/API/routes');
});
}
}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__45.txt b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__18.php
similarity index 61%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__45.txt
rename to tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__18.php
index 7a433b4..89a3dec 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__45.txt
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__18.php
@@ -1,14 +1,14 @@
+ * @return array
*/
protected function allowedAppends(): array
{
@@ -16,7 +16,7 @@ protected function allowedAppends(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultAppends(): array
{
@@ -24,7 +24,7 @@ protected function defaultAppends(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedFields(): array
{
@@ -34,7 +34,7 @@ protected function allowedFields(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedIncludes(): array
{
@@ -42,7 +42,7 @@ protected function allowedIncludes(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultIncludes(): array
{
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__16.txt b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__19.php
similarity index 65%
rename from tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__16.txt
rename to tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__19.php
index 05226fd..804bc9e 100644
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__16.txt
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__19.php
@@ -1,16 +1,16 @@
+ * @return array
*/
protected function allowedAppends(): array
{
@@ -18,7 +18,7 @@ protected function allowedAppends(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultAppends(): array
{
@@ -26,7 +26,7 @@ protected function defaultAppends(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedFields(): array
{
@@ -36,7 +36,7 @@ protected function allowedFields(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedFilters(): array
{
@@ -44,7 +44,7 @@ protected function allowedFilters(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedIncludes(): array
{
@@ -52,7 +52,7 @@ protected function allowedIncludes(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultIncludes(): array
{
@@ -60,7 +60,7 @@ protected function defaultIncludes(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedSorts(): array
{
@@ -68,7 +68,7 @@ protected function allowedSorts(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultSorts(): array
{
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__20.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__20.php
new file mode 100644
index 0000000..0c198a3
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__20.php
@@ -0,0 +1,28 @@
+validated());
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__21.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__21.php
new file mode 100644
index 0000000..2710975
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__21.php
@@ -0,0 +1,20 @@
+route('articleComment');
+ return $articleComment && Gate::check('delete', $articleComment);
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__22.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__22.php
new file mode 100644
index 0000000..16b668a
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__22.php
@@ -0,0 +1,20 @@
+route('articleComment');
+ return $articleComment && Gate::check('update', $articleComment);
+ }
+
+ public function toDTO(): UpdateArticleCommentDTO
+ {
+ return UpdateArticleCommentDTO::from($this->validated());
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__24.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__24.php
new file mode 100644
index 0000000..814263f
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__24.php
@@ -0,0 +1,20 @@
+route('articleComment');
+ return $articleComment && Gate::check('view', $articleComment);
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__25.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__25.php
new file mode 100644
index 0000000..368a4fd
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__25.php
@@ -0,0 +1,17 @@
+name('api.article_comments.create');
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__27.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__27.php
new file mode 100644
index 0000000..3098b2d
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__27.php
@@ -0,0 +1,7 @@
+name('api.article_comments.delete');
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__28.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__28.php
new file mode 100644
index 0000000..2fc2cd8
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__28.php
@@ -0,0 +1,7 @@
+name('api.article_comments.list');
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__29.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__29.php
new file mode 100644
index 0000000..872915f
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__29.php
@@ -0,0 +1,7 @@
+name('api.article_comments.update');
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__3.json b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__3.json
new file mode 100644
index 0000000..e7f3966
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__3.json
@@ -0,0 +1,32 @@
+{
+ "name": "demo/article-comment",
+ "description": "article-comment module",
+ "version": "1.0.0",
+ "authors": [
+ {
+ "name": "Example",
+ "email": "example@example.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\ArticleComment\\": "src/",
+ "Modules\\ArticleComment\\Database\\Factories\\": "database/factories/",
+ "Modules\\ArticleComment\\Database\\Seeders\\": "database/seeders/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\ArticleComment\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\ArticleComment\\Providers\\ArticleCommentServiceProvider",
+ "Modules\\ArticleComment\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": []
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__30.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__30.php
new file mode 100644
index 0000000..b6557d5
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__30.php
@@ -0,0 +1,7 @@
+name('api.article_comments.view');
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__31.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__31.php
new file mode 100644
index 0000000..7324e76
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__31.php
@@ -0,0 +1,80 @@
+ 'create-article-comment',
+ 'roles' => '',
+ ];
+
+ public function test_create_article_comment(): void
+ {
+ $this->actingAsTestUser();
+
+ $data = $this->getTestData();
+
+ $this->postJson(route('api.article_comments.create'), $data)
+ ->assertCreated()
+ ->assertJson(fn (AssertableJson $json) =>
+ $json->has('data', fn (AssertableJson $json) =>
+ $json->has('id')
+ ->whereAll($data)
+ ->etc()
+ )
+ );
+
+ $this->assertDatabaseHas(ArticleComment::class, $data);
+ }
+
+ public function test_create_article_comment_with_invalid_data(): void
+ {
+ $this->actingAsTestUser();
+
+ $this->postJson(route('api.article_comments.create'), [])
+ ->assertUnprocessable()
+ ->assertJsonValidationErrors([
+ // TODO: add expected validation errors here
+ ]);
+ }
+
+ public function test_create_article_comment_unauthenticated(): void
+ {
+ $data = $this->getTestData();
+
+ $this->postJson(route('api.article_comments.create'), $data)
+ ->assertUnauthorized();
+ }
+
+ public function test_create_article_comment_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $data = $this->getTestData();
+
+ $this->postJson(route('api.article_comments.create'), $data)
+ ->assertForbidden();
+ }
+
+ protected function getTestData(array $mergeData = []): array
+ {
+ return array_merge([
+ // TODO: add fields here
+ ], $mergeData);
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__32.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__32.php
new file mode 100644
index 0000000..8b6e412
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__32.php
@@ -0,0 +1,62 @@
+ 'delete-article-comment',
+ 'roles' => '',
+ ];
+
+ public function test_delete_article_comment(): void
+ {
+ $this->actingAsTestUser();
+
+ $articleComment = ArticleComment::factory()->create();
+
+ $this->deleteJson(route('api.article_comments.delete', ['articleComment' => $articleComment->getKey()]))
+ ->assertNoContent();
+
+ $this->assertNull(ArticleComment::find($articleComment->getKey()));
+ }
+
+ public function test_delete_article_comment_unauthenticated(): void
+ {
+ $articleComment = ArticleComment::factory()->create();
+
+ $this->deleteJson(route('api.article_comments.delete', ['articleComment' => $articleComment->getKey()]))
+ ->assertUnauthorized();
+ }
+
+ public function test_delete_article_comment_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $articleComment = ArticleComment::factory()->create();
+
+ $this->deleteJson(route('api.article_comments.delete', ['articleComment' => $articleComment->getKey()]))
+ ->assertForbidden();
+ }
+
+ public function test_delete_not_existing_article_comment(): void
+ {
+ $this->actingAsTestUser();
+
+ $this->deleteJson(route('api.article_comments.delete', ['articleComment' => 7777]))
+ ->assertNotFound();
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__33.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__33.php
new file mode 100644
index 0000000..76e410b
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__33.php
@@ -0,0 +1,58 @@
+ 'view-article-comment',
+ 'roles' => '',
+ ];
+
+ public function test_list_article_comments(): void
+ {
+ $this->actingAsTestUser();
+
+ ArticleComment::factory()->count(3)->create();
+
+ $this->getJson(route('api.article_comments.list'))
+ ->assertOk()
+ ->assertJsonStructure([
+ 'links',
+ 'meta',
+ 'data'
+ ])
+ ->assertJsonCount(3, 'data');
+ }
+
+ public function test_list_article_comments_unauthenticated(): void
+ {
+ ArticleComment::factory()->count(3)->create();
+
+ $this->getJson(route('api.article_comments.list'))
+ ->assertUnauthorized();
+ }
+
+ public function test_list_article_comments_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ ArticleComment::factory()->count(3)->create();
+
+ $this->getJson(route('api.article_comments.list'))
+ ->assertForbidden();
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__34.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__34.php
new file mode 100644
index 0000000..eeb040d
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__34.php
@@ -0,0 +1,100 @@
+ 'update-article-comment',
+ 'roles' => '',
+ ];
+
+ public function test_update_article_comment(): void
+ {
+ $this->actingAsTestUser();
+
+ $articleComment = ArticleComment::factory()->create();
+
+ $data = $this->getTestData();
+ $expectedData = array_merge($data, [
+ 'id' => $articleComment->getKey(),
+ ]);
+
+ $this->patchJson(route('api.article_comments.update', ['articleComment' => $articleComment->getKey()]), $data)
+ ->assertOk()
+ ->assertJson(fn (AssertableJson $json) =>
+ $json->has('data', fn (AssertableJson $json) =>
+ $json->whereAll($expectedData)
+ ->etc()
+ )
+ );
+
+ $this->assertDatabaseHas(ArticleComment::class, $expectedData);
+ }
+
+ public function test_update_article_comment_with_invalid_data(): void
+ {
+ $this->actingAsTestUser();
+
+ $articleComment = ArticleComment::factory()->create();
+
+ $this->patchJson(route('api.article_comments.update', ['articleComment' => $articleComment->getKey()]), [])
+ ->assertUnprocessable()
+ ->assertJsonValidationErrors([
+ // TODO: add expected validation errors here
+ ]);
+ }
+
+ public function test_update_article_comment_unauthenticated(): void
+ {
+ $articleComment = ArticleComment::factory()->create();
+
+ $data = $this->getTestData();
+
+ $this->patchJson(route('api.article_comments.update', ['articleComment' => $articleComment->getKey()]), $data)
+ ->assertUnauthorized();
+ }
+
+ public function test_update_article_comment_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $articleComment = ArticleComment::factory()->create();
+
+ $data = $this->getTestData();
+
+ $this->patchJson(route('api.article_comments.update', ['articleComment' => $articleComment->getKey()]), $data)
+ ->assertForbidden();
+ }
+
+ public function test_update_non_existing_article_comment(): void
+ {
+ $this->actingAsTestUser();
+
+ $data = $this->getTestData();
+
+ $this->patchJson(route('api.article_comments.update', ['articleComment' => 7777]), $data)
+ ->assertNotFound();
+ }
+
+ protected function getTestData(array $mergeData = []): array
+ {
+ return array_merge([
+ // TODO: add fields here
+ ], $mergeData);
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__35.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__35.php
new file mode 100644
index 0000000..370958c
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__35.php
@@ -0,0 +1,68 @@
+ 'view-article-comment',
+ 'roles' => '',
+ ];
+
+ public function test_view_article_comment(): void
+ {
+ $this->actingAsTestUser();
+
+ $articleComment = ArticleComment::factory()->create();
+ $expectedData = $articleComment->toArray();
+
+ $this->getJson(route('api.article_comments.view', ['articleComment' => $articleComment->getKey()]))
+ ->assertOk()
+ ->assertJson(fn (AssertableJson $json) =>
+ $json->has('data', fn (AssertableJson $json) =>
+ $json->whereAll($expectedData)
+ ->etc()
+ )
+ );
+ }
+
+ public function test_view_article_comment_unauthenticated(): void
+ {
+ $articleComment = ArticleComment::factory()->create();
+
+ $this->getJson(route('api.article_comments.view', ['articleComment' => $articleComment->getKey()]))
+ ->assertUnauthorized();
+ }
+
+ public function test_view_article_comment_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $articleComment = ArticleComment::factory()->create();
+
+ $this->getJson(route('api.article_comments.view', ['articleComment' => $articleComment->getKey()]))
+ ->assertForbidden();
+ }
+
+ public function test_view_not_existing_article_comment(): void
+ {
+ $this->actingAsTestUser();
+
+ $this->getJson(route('api.article_comments.view', ['articleComment' => 7777]))
+ ->assertNotFound();
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__4.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__4.php
new file mode 100644
index 0000000..28b67d9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__4.php
@@ -0,0 +1,33 @@
+|ArticleComment create($attributes = [], ?ArticleComment $parent = null)
+ * @method \Illuminate\Support\Collection createMany(iterable $records)
+ * @method ArticleComment createOne($attributes = [])
+ * @method \Illuminate\Support\Collection|ArticleComment make($attributes = [], ?ArticleComment $parent = null)
+ * @method ArticleComment makeOne($attributes = [])
+ */
+class ArticleCommentFactory extends Factory
+{
+ /**
+ * The name of the factory's corresponding model.
+ *
+ * @var class-string
+ */
+ protected $model = ArticleComment::class;
+
+ /**
+ * Define the model's default state.
+ */
+ public function definition(): array
+ {
+ return [
+ // TODO: add fields here
+ ];
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__63.txt b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__5.php
similarity index 76%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__63.txt
rename to tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__5.php
index 917126a..6f9bd1b 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__63.txt
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__5.php
@@ -11,7 +11,7 @@
*/
public function up(): void
{
- Schema::create('comments', static function (Blueprint $table) {
+ Schema::create('article_comments', static function (Blueprint $table) {
$table->id();
$table->timestamps();
@@ -23,6 +23,6 @@ public function up(): void
*/
public function down(): void
{
- Schema::dropIfExists('comments');
+ Schema::dropIfExists('article_comments');
}
};
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__6.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__6.php
new file mode 100644
index 0000000..7e1e80a
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__6.php
@@ -0,0 +1,45 @@
+handle(new CreatePermissionDTO(
+ name: 'view-article-comment',
+ display_name: 'View any "article-comments"',
+ group: 'article-comments'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'create-article-comment',
+ display_name: 'Create "article-comments"',
+ group: 'article-comments'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'update-article-comment',
+ display_name: 'Update any "article-comments"',
+ group: 'article-comments'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'delete-article-comment',
+ display_name: 'Delete any "article-comments"',
+ group: 'article-comments'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'force-delete-article-comment',
+ display_name: 'Force delete any "article-comments"',
+ group: 'article-comments'
+ ));
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__7.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__7.php
new file mode 100644
index 0000000..27192d2
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__7.php
@@ -0,0 +1,27 @@
+all());
+ }
+
+ public function asController(CreateArticleCommentRequest $request): JsonResponse
+ {
+ $articleComment = $this->handle($request->toDTO());
+
+ return (new ArticleCommentResource($articleComment))->created();
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__8.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__8.php
new file mode 100644
index 0000000..710f7e1
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__8.php
@@ -0,0 +1,25 @@
+delete();
+ }
+
+ public function asController(DeleteArticleCommentRequest $request, ArticleComment $articleComment): Response
+ {
+ $this->handle($articleComment);
+
+ return $this->noContent();
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__9.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__9.php
new file mode 100644
index 0000000..865dd73
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__api__module__9.php
@@ -0,0 +1,28 @@
+build()
+ ->paginate();
+ }
+
+ public function asController(ListArticleCommentsRequest $request): AnonymousResourceCollection
+ {
+ return ArticleCommentResource::collection($this->handle($request));
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__1.json b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__1.json
new file mode 100644
index 0000000..d13e452
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__1.json
@@ -0,0 +1,55 @@
+{
+ "name": "laraneat/laraneat",
+ "type": "project",
+ "description": "The Laraneat framework.",
+ "keywords": [
+ "laraneat",
+ "laravel",
+ "apiato",
+ "php",
+ "framework"
+ ],
+ "license": "MIT",
+ "require": {
+ "php": "^8.1",
+ "demo/article-comment": "*",
+ "laravel/framework": "^10.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.5.9"
+ },
+ "autoload": {
+ "classmap": [
+ "database"
+ ],
+ "psr-4": {
+ "App\\": "app/",
+ "Modules\\": "modules/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "dont-discover": []
+ }
+ },
+ "config": {
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true,
+ "allow-plugins": {
+ "pestphp/pest-plugin": true,
+ "php-http/discovery": true
+ }
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": true,
+ "repositories": [
+ {
+ "type": "path",
+ "url": "modules/*",
+ "options": {
+ "symlink": true
+ }
+ }
+ ]
+}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__14.txt b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__10.php
similarity index 63%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__14.txt
rename to tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__10.php
index 3d39542..ba84e41 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__14.txt
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__10.php
@@ -1,16 +1,14 @@
namespace('App\\Modules\\Blog\\UI\\WEB\\Controllers')
+ // ->namespace('Modules\\ArticleComment\\UI\\WEB\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/WEB/Routes'));
+ $this->loadRoutesFromDirectory(__DIR__.'/../UI/WEB/routes');
});
}
@@ -51,9 +49,9 @@ protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
-// ->namespace('App\\Modules\\Blog\\UI\\API\\Controllers')
+ // ->namespace('Modules\\ArticleComment\\UI\\API\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/API/Routes'));
+ $this->loadRoutesFromDirectory(__DIR__.'/../UI/API/routes');
});
}
}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__3.json b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__3.json
new file mode 100644
index 0000000..e7f3966
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__3.json
@@ -0,0 +1,32 @@
+{
+ "name": "demo/article-comment",
+ "description": "article-comment module",
+ "version": "1.0.0",
+ "authors": [
+ {
+ "name": "Example",
+ "email": "example@example.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\ArticleComment\\": "src/",
+ "Modules\\ArticleComment\\Database\\Factories\\": "database/factories/",
+ "Modules\\ArticleComment\\Database\\Seeders\\": "database/seeders/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\ArticleComment\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\ArticleComment\\Providers\\ArticleCommentServiceProvider",
+ "Modules\\ArticleComment\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": []
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__4.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__4.php
new file mode 100644
index 0000000..28b67d9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__4.php
@@ -0,0 +1,33 @@
+|ArticleComment create($attributes = [], ?ArticleComment $parent = null)
+ * @method \Illuminate\Support\Collection createMany(iterable $records)
+ * @method ArticleComment createOne($attributes = [])
+ * @method \Illuminate\Support\Collection|ArticleComment make($attributes = [], ?ArticleComment $parent = null)
+ * @method ArticleComment makeOne($attributes = [])
+ */
+class ArticleCommentFactory extends Factory
+{
+ /**
+ * The name of the factory's corresponding model.
+ *
+ * @var class-string
+ */
+ protected $model = ArticleComment::class;
+
+ /**
+ * Define the model's default state.
+ */
+ public function definition(): array
+ {
+ return [
+ // TODO: add fields here
+ ];
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__64.txt b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__5.php
similarity index 76%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__64.txt
rename to tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__5.php
index f39c303..6f9bd1b 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__64.txt
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__5.php
@@ -11,7 +11,7 @@
*/
public function up(): void
{
- Schema::create('posts', static function (Blueprint $table) {
+ Schema::create('article_comments', static function (Blueprint $table) {
$table->id();
$table->timestamps();
@@ -23,6 +23,6 @@ public function up(): void
*/
public function down(): void
{
- Schema::dropIfExists('posts');
+ Schema::dropIfExists('article_comments');
}
};
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__6.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__6.php
new file mode 100644
index 0000000..7e1e80a
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__6.php
@@ -0,0 +1,45 @@
+handle(new CreatePermissionDTO(
+ name: 'view-article-comment',
+ display_name: 'View any "article-comments"',
+ group: 'article-comments'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'create-article-comment',
+ display_name: 'Create "article-comments"',
+ group: 'article-comments'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'update-article-comment',
+ display_name: 'Update any "article-comments"',
+ group: 'article-comments'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'delete-article-comment',
+ display_name: 'Delete any "article-comments"',
+ group: 'article-comments'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'force-delete-article-comment',
+ display_name: 'Force delete any "article-comments"',
+ group: 'article-comments'
+ ));
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__11.txt b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__7.php
similarity index 67%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__11.txt
rename to tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__7.php
index 2a66463..1b97872 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_can_set_custom_model__11.txt
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__7.php
@@ -1,13 +1,13 @@
can('view-article-comment');
+ }
+
+ /**
+ * Determine whether the user can view the model.
+ */
+ public function view(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('view-article-comment');
+ }
+
+ /**
+ * Determine whether the user can create models.
+ */
+ public function create(User $user): bool
+ {
+ return $user->can('create-article-comment');
+ }
+
+ /**
+ * Determine whether the user can update the model.
+ */
+ public function update(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('update-article-comment');
+ }
+
+ /**
+ * Determine whether the user can delete the model.
+ */
+ public function delete(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('delete-article-comment');
+ }
+
+ /**
+ * Determine whether the user can restore the model.
+ */
+ public function restore(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('delete-article-comment');
+ }
+
+ /**
+ * Determine whether the user can permanently delete the model.
+ */
+ public function forceDelete(User $user, ArticleComment $articleComment): bool
+ {
+ return $user->can('force-delete-article-comment');
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__9.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__9.php
new file mode 100644
index 0000000..1696363
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__base__module__9.php
@@ -0,0 +1,102 @@
+loadConfigurations();
+ }
+
+ /**
+ * Bootstrap services.
+ */
+ public function boot(): void
+ {
+ $this->loadMigrations();
+ // $this->loadCommands();
+ // $this->loadTranslations();
+ // $this->loadViews();
+ }
+
+ /**
+ * Register configuration files.
+ */
+ public function loadConfigurations(): void
+ {
+ $sourcePath = __DIR__.'/../../config/article-comment.php';
+ $configsPath = $this->app->configPath('article-comment.php');
+
+ $this->mergeConfigFrom($sourcePath, 'article-comment');
+
+ $this->publishes([
+ $sourcePath => $configsPath
+ ], 'article-comment-config');
+ }
+
+ /**
+ * Register migrations.
+ */
+ public function loadMigrations(): void
+ {
+ $sourcePath = __DIR__.'/../../database/migrations';
+ $migrationsPath = $this->app->databasePath('migrations');
+
+ $this->loadMigrationsFrom($sourcePath);
+
+ $this->publishes([
+ $sourcePath => $migrationsPath
+ ], 'article-comment-migrations');
+ }
+
+ /**
+ * Register artisan commands.
+ */
+ public function loadCommands(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ 'Modules\\ArticleComment\\UI\\CLI\\Commands' => __DIR__.'/../UI/CLI/Commands',
+ ]);
+ }
+ }
+
+ /**
+ * Register translations.
+ */
+ public function loadTranslations(): void
+ {
+ $sourcePath = __DIR__.'/../../lang';
+ $langPath = $this->app->langPath('modules/article-comment');
+
+ $this->loadTranslationsFrom($sourcePath, 'article-comment');
+
+ $this->publishes([
+ $sourcePath => $langPath,
+ ], 'article-comment-translations');
+ }
+
+ /**
+ * Register views.
+ */
+ public function loadViews(): void
+ {
+ $sourcePath = __DIR__.'/../../resources/views';
+ $viewsPath = $this->app->resourcePath('views/modules/article-comment');
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths('article-comment'), [$sourcePath]),
+ 'article-comment'
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath
+ ], 'article-comment-views');
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__1.json b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__1.json
new file mode 100644
index 0000000..d13e452
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__1.json
@@ -0,0 +1,55 @@
+{
+ "name": "laraneat/laraneat",
+ "type": "project",
+ "description": "The Laraneat framework.",
+ "keywords": [
+ "laraneat",
+ "laravel",
+ "apiato",
+ "php",
+ "framework"
+ ],
+ "license": "MIT",
+ "require": {
+ "php": "^8.1",
+ "demo/article-comment": "*",
+ "laravel/framework": "^10.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.5.9"
+ },
+ "autoload": {
+ "classmap": [
+ "database"
+ ],
+ "psr-4": {
+ "App\\": "app/",
+ "Modules\\": "modules/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "dont-discover": []
+ }
+ },
+ "config": {
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true,
+ "allow-plugins": {
+ "pestphp/pest-plugin": true,
+ "php-http/discovery": true
+ }
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": true,
+ "repositories": [
+ {
+ "type": "path",
+ "url": "modules/*",
+ "options": {
+ "symlink": true
+ }
+ }
+ ]
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__3.json b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__3.json
new file mode 100644
index 0000000..e7f3966
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__3.json
@@ -0,0 +1,32 @@
+{
+ "name": "demo/article-comment",
+ "description": "article-comment module",
+ "version": "1.0.0",
+ "authors": [
+ {
+ "name": "Example",
+ "email": "example@example.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\ArticleComment\\": "src/",
+ "Modules\\ArticleComment\\Database\\Factories\\": "database/factories/",
+ "Modules\\ArticleComment\\Database\\Seeders\\": "database/seeders/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\ArticleComment\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\ArticleComment\\Providers\\ArticleCommentServiceProvider",
+ "Modules\\ArticleComment\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": []
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__4.php b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__4.php
new file mode 100644
index 0000000..1696363
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__4.php
@@ -0,0 +1,102 @@
+loadConfigurations();
+ }
+
+ /**
+ * Bootstrap services.
+ */
+ public function boot(): void
+ {
+ $this->loadMigrations();
+ // $this->loadCommands();
+ // $this->loadTranslations();
+ // $this->loadViews();
+ }
+
+ /**
+ * Register configuration files.
+ */
+ public function loadConfigurations(): void
+ {
+ $sourcePath = __DIR__.'/../../config/article-comment.php';
+ $configsPath = $this->app->configPath('article-comment.php');
+
+ $this->mergeConfigFrom($sourcePath, 'article-comment');
+
+ $this->publishes([
+ $sourcePath => $configsPath
+ ], 'article-comment-config');
+ }
+
+ /**
+ * Register migrations.
+ */
+ public function loadMigrations(): void
+ {
+ $sourcePath = __DIR__.'/../../database/migrations';
+ $migrationsPath = $this->app->databasePath('migrations');
+
+ $this->loadMigrationsFrom($sourcePath);
+
+ $this->publishes([
+ $sourcePath => $migrationsPath
+ ], 'article-comment-migrations');
+ }
+
+ /**
+ * Register artisan commands.
+ */
+ public function loadCommands(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ 'Modules\\ArticleComment\\UI\\CLI\\Commands' => __DIR__.'/../UI/CLI/Commands',
+ ]);
+ }
+ }
+
+ /**
+ * Register translations.
+ */
+ public function loadTranslations(): void
+ {
+ $sourcePath = __DIR__.'/../../lang';
+ $langPath = $this->app->langPath('modules/article-comment');
+
+ $this->loadTranslationsFrom($sourcePath, 'article-comment');
+
+ $this->publishes([
+ $sourcePath => $langPath,
+ ], 'article-comment-translations');
+ }
+
+ /**
+ * Register views.
+ */
+ public function loadViews(): void
+ {
+ $sourcePath = __DIR__.'/../../resources/views';
+ $viewsPath = $this->app->resourcePath('views/modules/article-comment');
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths('article-comment'), [$sourcePath]),
+ 'article-comment'
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath
+ ], 'article-comment-views');
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__12.txt b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__5.php
similarity index 63%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__12.txt
rename to tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__5.php
index 8e33d3a..ba84e41 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__12.txt
+++ b/tests/__snapshots__/files/ModuleMakeCommandTest__it_generates_a__plain__module__5.php
@@ -1,16 +1,14 @@
namespace('App\\Modules\\Article\\UI\\WEB\\Controllers')
+ // ->namespace('Modules\\ArticleComment\\UI\\WEB\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/WEB/Routes'));
+ $this->loadRoutesFromDirectory(__DIR__.'/../UI/WEB/routes');
});
}
@@ -51,9 +49,9 @@ protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
-// ->namespace('App\\Modules\\Article\\UI\\API\\Controllers')
+ // ->namespace('Modules\\ArticleComment\\UI\\API\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/API/Routes'));
+ $this->loadRoutesFromDirectory(__DIR__.'/../UI/API/routes');
});
}
}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_add_aliases__1.json b/tests/__snapshots__/files/ModuleTest__it_can_add_aliases__1.json
new file mode 100644
index 0000000..da14fd9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_add_aliases__1.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_add_aliases__2.json b/tests/__snapshots__/files/ModuleTest__it_can_add_aliases__2.json
new file mode 100644
index 0000000..ebe9ac3
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_add_aliases__2.json
@@ -0,0 +1,33 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade",
+ "foo": "Modules\\Author\\Services\\Foo",
+ "bar": "Modules\\Bar\\Services\\Bar"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_add_aliases_via_ModuleConfigWriter__1.json b/tests/__snapshots__/files/ModuleTest__it_can_add_aliases_via_ModuleConfigWriter__1.json
new file mode 100644
index 0000000..da14fd9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_add_aliases_via_ModuleConfigWriter__1.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_add_aliases_via_ModuleConfigWriter__2.json b/tests/__snapshots__/files/ModuleTest__it_can_add_aliases_via_ModuleConfigWriter__2.json
new file mode 100644
index 0000000..f9631aa
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_add_aliases_via_ModuleConfigWriter__2.json
@@ -0,0 +1,32 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade",
+ "bar": "Modules\\Bar\\Services\\Bar"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_add_providers__1.json b/tests/__snapshots__/files/ModuleTest__it_can_add_providers__1.json
new file mode 100644
index 0000000..da14fd9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_add_providers__1.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_add_providers__2.json b/tests/__snapshots__/files/ModuleTest__it_can_add_providers__2.json
new file mode 100644
index 0000000..4491948
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_add_providers__2.json
@@ -0,0 +1,33 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider",
+ "Modules\\Author\\Providers\\FooServiceProvider",
+ "Modules\\Foo\\Providers\\BarServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_add_providers_via_ModuleConfigWriter__1.json b/tests/__snapshots__/files/ModuleTest__it_can_add_providers_via_ModuleConfigWriter__1.json
new file mode 100644
index 0000000..da14fd9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_add_providers_via_ModuleConfigWriter__1.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_add_providers_via_ModuleConfigWriter__2.json b/tests/__snapshots__/files/ModuleTest__it_can_add_providers_via_ModuleConfigWriter__2.json
new file mode 100644
index 0000000..af000ba
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_add_providers_via_ModuleConfigWriter__2.json
@@ -0,0 +1,32 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider",
+ "Modules\\Foo\\Providers\\BarServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_set_aliases__1.json b/tests/__snapshots__/files/ModuleTest__it_can_set_aliases__1.json
new file mode 100644
index 0000000..da14fd9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_set_aliases__1.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_set_aliases__2.json b/tests/__snapshots__/files/ModuleTest__it_can_set_aliases__2.json
new file mode 100644
index 0000000..8505b7d
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_set_aliases__2.json
@@ -0,0 +1,32 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "foo": "Modules\\Author\\Services\\Foo",
+ "bar": "Modules\\Bar\\Services\\Bar"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_set_providers__1.json b/tests/__snapshots__/files/ModuleTest__it_can_set_providers__1.json
new file mode 100644
index 0000000..da14fd9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_set_providers__1.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_set_providers__2.json b/tests/__snapshots__/files/ModuleTest__it_can_set_providers__2.json
new file mode 100644
index 0000000..ab6c0e8
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_set_providers__2.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\FooServiceProvider",
+ "Modules\\Foo\\Providers\\BarServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_update_aliases_via_ModuleConfigWriter__1.json b/tests/__snapshots__/files/ModuleTest__it_can_update_aliases_via_ModuleConfigWriter__1.json
new file mode 100644
index 0000000..da14fd9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_update_aliases_via_ModuleConfigWriter__1.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_update_aliases_via_ModuleConfigWriter__2.json b/tests/__snapshots__/files/ModuleTest__it_can_update_aliases_via_ModuleConfigWriter__2.json
new file mode 100644
index 0000000..8505b7d
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_update_aliases_via_ModuleConfigWriter__2.json
@@ -0,0 +1,32 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "foo": "Modules\\Author\\Services\\Foo",
+ "bar": "Modules\\Bar\\Services\\Bar"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_update_providers_via_ModuleConfigWriter__1.json b/tests/__snapshots__/files/ModuleTest__it_can_update_providers_via_ModuleConfigWriter__1.json
new file mode 100644
index 0000000..da14fd9
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_update_providers_via_ModuleConfigWriter__1.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModuleTest__it_can_update_providers_via_ModuleConfigWriter__2.json b/tests/__snapshots__/files/ModuleTest__it_can_update_providers_via_ModuleConfigWriter__2.json
new file mode 100644
index 0000000..ab6c0e8
--- /dev/null
+++ b/tests/__snapshots__/files/ModuleTest__it_can_update_providers_via_ModuleConfigWriter__2.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\FooServiceProvider",
+ "Modules\\Foo\\Providers\\BarServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/__snapshots__/files/ModulesRepositoryTest__it_can_sync_modules_with_composer__1.json b/tests/__snapshots__/files/ModulesRepositoryTest__it_can_sync_modules_with_composer__1.json
new file mode 100644
index 0000000..1977705
--- /dev/null
+++ b/tests/__snapshots__/files/ModulesRepositoryTest__it_can_sync_modules_with_composer__1.json
@@ -0,0 +1,45 @@
+{
+ "name": "laraneat/laraneat",
+ "type": "project",
+ "description": "The Laraneat framework.",
+ "keywords": [
+ "laraneat",
+ "laravel",
+ "apiato",
+ "php",
+ "framework"
+ ],
+ "license": "MIT",
+ "require": {
+ "php": "^8.1",
+ "laravel/framework": "^10.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.5.9"
+ },
+ "autoload": {
+ "classmap": [
+ "database"
+ ],
+ "psr-4": {
+ "App\\": "app/",
+ "Modules\\": "modules/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "dont-discover": []
+ }
+ },
+ "config": {
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true,
+ "allow-plugins": {
+ "pestphp/pest-plugin": true,
+ "php-http/discovery": true
+ }
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": true
+}
diff --git a/tests/__snapshots__/files/ModulesRepositoryTest__it_can_sync_modules_with_composer__2.json b/tests/__snapshots__/files/ModulesRepositoryTest__it_can_sync_modules_with_composer__2.json
new file mode 100644
index 0000000..57b4f73
--- /dev/null
+++ b/tests/__snapshots__/files/ModulesRepositoryTest__it_can_sync_modules_with_composer__2.json
@@ -0,0 +1,59 @@
+{
+ "name": "laraneat/laraneat",
+ "type": "project",
+ "description": "The Laraneat framework.",
+ "keywords": [
+ "laraneat",
+ "laravel",
+ "apiato",
+ "php",
+ "framework"
+ ],
+ "license": "MIT",
+ "require": {
+ "php": "^8.1",
+ "laraneat/article": "*",
+ "laraneat/article-category": "*",
+ "laraneat/author": "*",
+ "laraneat/empty": "*",
+ "laraneat/location": "*",
+ "laravel/framework": "^10.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.5.9"
+ },
+ "autoload": {
+ "classmap": [
+ "database"
+ ],
+ "psr-4": {
+ "App\\": "app/",
+ "Modules\\": "modules/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "dont-discover": []
+ }
+ },
+ "config": {
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true,
+ "allow-plugins": {
+ "pestphp/pest-plugin": true,
+ "php-http/discovery": true
+ }
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": true,
+ "repositories": [
+ {
+ "type": "path",
+ "url": "modules/*",
+ "options": {
+ "symlink": true
+ }
+ }
+ ]
+}
diff --git a/tests/__snapshots__/files/NotificationMakeCommandTest__it_generates__plain__notification_for_the_module__1.php b/tests/__snapshots__/files/NotificationMakeCommandTest__it_generates__plain__notification_for_the_module__1.php
new file mode 100644
index 0000000..1b65cc0
--- /dev/null
+++ b/tests/__snapshots__/files/NotificationMakeCommandTest__it_generates__plain__notification_for_the_module__1.php
@@ -0,0 +1,36 @@
+
+ */
+ public function via(object $notifiable): array
+ {
+ return ['mail', 'database'];
+ }
+
+ /**
+ * Get the array representation of the notification.
+ */
+ public function toArray(object $notifiable): array
+ {
+ return [
+ //
+ ];
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/NotificationMakeCommandTest__it_generated_correct_queued_notification_file_with_content__1.txt b/tests/__snapshots__/files/NotificationMakeCommandTest__it_generates__queued__notification_for_the_module__1.php
similarity index 56%
rename from tests/Commands/Generators/__snapshots__/NotificationMakeCommandTest__it_generated_correct_queued_notification_file_with_content__1.txt
rename to tests/__snapshots__/files/NotificationMakeCommandTest__it_generates__queued__notification_for_the_module__1.php
index 9c1c072..14891e9 100644
--- a/tests/Commands/Generators/__snapshots__/NotificationMakeCommandTest__it_generated_correct_queued_notification_file_with_content__1.txt
+++ b/tests/__snapshots__/files/NotificationMakeCommandTest__it_generates__queued__notification_for_the_module__1.php
@@ -1,16 +1,19 @@
*/
- public function via($notifiable): array
+ public function via(object $notifiable): array
{
return ['mail'];
}
@@ -27,18 +32,20 @@ public function via($notifiable): array
/**
* Get the mail representation of the notification.
*/
- public function toMail($notifiable): MailMessage
+ public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->line('The introduction to the notification.')
- ->action('Notification Action', 'https://laravel.com')
+ ->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
+ *
+ * @return array
*/
- public function toArray($notifiable): array
+ public function toArray(object $notifiable): array
{
return [
//
diff --git a/tests/__snapshots__/files/ObserverMakeCommandTest__it_generates_observer_for_the_module__1.php b/tests/__snapshots__/files/ObserverMakeCommandTest__it_generates_observer_for_the_module__1.php
new file mode 100644
index 0000000..5fc6ec5
--- /dev/null
+++ b/tests/__snapshots__/files/ObserverMakeCommandTest__it_generates_observer_for_the_module__1.php
@@ -0,0 +1,48 @@
+can('view-author');
+ }
+
+ /**
+ * Determine whether the user can view the model.
+ */
+ public function view(User $user, Author $author): bool
+ {
+ return $user->can('view-author');
+ }
+
+ /**
+ * Determine whether the user can create models.
+ */
+ public function create(User $user): bool
+ {
+ return $user->can('create-author');
+ }
+
+ /**
+ * Determine whether the user can update the model.
+ */
+ public function update(User $user, Author $author): bool
+ {
+ return $user->can('update-author');
+ }
+
+ /**
+ * Determine whether the user can delete the model.
+ */
+ public function delete(User $user, Author $author): bool
+ {
+ return $user->can('delete-author');
+ }
+
+ /**
+ * Determine whether the user can restore the model.
+ */
+ public function restore(User $user, Author $author): bool
+ {
+ return $user->can('delete-author');
+ }
+
+ /**
+ * Determine whether the user can permanently delete the model.
+ */
+ public function forceDelete(User $user, Author $author): bool
+ {
+ return $user->can('force-delete-author');
+ }
+}
diff --git a/tests/__snapshots__/files/PolicyMakeCommandTest__it_generates_plain_policy_for_the_module__1.php b/tests/__snapshots__/files/PolicyMakeCommandTest__it_generates_plain_policy_for_the_module__1.php
new file mode 100644
index 0000000..00de928
--- /dev/null
+++ b/tests/__snapshots__/files/PolicyMakeCommandTest__it_generates_plain_policy_for_the_module__1.php
@@ -0,0 +1,8 @@
+>
+ */
+ protected $listen = [];
+
+ /**
+ * Register any events for your application.
+ */
+ public function boot(): void
+ {
+ //
+ }
+}
diff --git a/tests/__snapshots__/files/ProviderMakeCommandTest__it_generates__module__provider_for_the_module__1.php b/tests/__snapshots__/files/ProviderMakeCommandTest__it_generates__module__provider_for_the_module__1.php
new file mode 100644
index 0000000..184b779
--- /dev/null
+++ b/tests/__snapshots__/files/ProviderMakeCommandTest__it_generates__module__provider_for_the_module__1.php
@@ -0,0 +1,102 @@
+loadConfigurations();
+ }
+
+ /**
+ * Bootstrap services.
+ */
+ public function boot(): void
+ {
+ $this->loadMigrations();
+ // $this->loadCommands();
+ // $this->loadTranslations();
+ // $this->loadViews();
+ }
+
+ /**
+ * Register configuration files.
+ */
+ public function loadConfigurations(): void
+ {
+ $sourcePath = __DIR__.'/../../config/author.php';
+ $configsPath = $this->app->configPath('author.php');
+
+ $this->mergeConfigFrom($sourcePath, 'author');
+
+ $this->publishes([
+ $sourcePath => $configsPath
+ ], 'author-config');
+ }
+
+ /**
+ * Register migrations.
+ */
+ public function loadMigrations(): void
+ {
+ $sourcePath = __DIR__.'/../../database/migrations';
+ $migrationsPath = $this->app->databasePath('migrations');
+
+ $this->loadMigrationsFrom($sourcePath);
+
+ $this->publishes([
+ $sourcePath => $migrationsPath
+ ], 'author-migrations');
+ }
+
+ /**
+ * Register artisan commands.
+ */
+ public function loadCommands(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ 'Modules\\Author\\UI\\CLI\\Commands' => __DIR__.'/../UI/CLI/Commands',
+ ]);
+ }
+ }
+
+ /**
+ * Register translations.
+ */
+ public function loadTranslations(): void
+ {
+ $sourcePath = __DIR__.'/../../lang';
+ $langPath = $this->app->langPath('modules/author');
+
+ $this->loadTranslationsFrom($sourcePath, 'author');
+
+ $this->publishes([
+ $sourcePath => $langPath,
+ ], 'author-translations');
+ }
+
+ /**
+ * Register views.
+ */
+ public function loadViews(): void
+ {
+ $sourcePath = __DIR__.'/../../resources/views';
+ $viewsPath = $this->app->resourcePath('views/modules/author');
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths('author'), [$sourcePath]),
+ 'author'
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath
+ ], 'author-views');
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/ProviderMakeCommandTest__it_generated_correct_provider_file_with_content__1.txt b/tests/__snapshots__/files/ProviderMakeCommandTest__it_generates__plain__provider_for_the_module__1.php
similarity index 53%
rename from tests/Commands/Generators/__snapshots__/ProviderMakeCommandTest__it_generated_correct_provider_file_with_content__1.txt
rename to tests/__snapshots__/files/ProviderMakeCommandTest__it_generates__plain__provider_for_the_module__1.php
index cd61c64..f5a2650 100644
--- a/tests/Commands/Generators/__snapshots__/ProviderMakeCommandTest__it_generated_correct_provider_file_with_content__1.txt
+++ b/tests/__snapshots__/files/ProviderMakeCommandTest__it_generates__plain__provider_for_the_module__1.php
@@ -1,13 +1,13 @@
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('Modules\\Author\\UI\\WEB\\Controllers')
+ ->group(function () {
+ $this->loadRoutesFromDirectory(__DIR__.'/../UI/WEB/routes');
+ });
+ }
+
+ /**
+ * Define the "api" routes for the application.
+ * These routes are typically stateless.
+ */
+ protected function mapApiRoutes(): void
+ {
+ Route::prefix('api')
+ ->middleware('api')
+ // ->namespace('Modules\\Author\\UI\\API\\Controllers')
+ ->group(function () {
+ $this->loadRoutesFromDirectory(__DIR__.'/../UI/API/routes');
+ });
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__14.txt b/tests/__snapshots__/files/QueryWizardMakeCommandTest__it_generates__eloquent__query_wizard_for_the_module__1.php
similarity index 65%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__14.txt
rename to tests/__snapshots__/files/QueryWizardMakeCommandTest__it_generates__eloquent__query_wizard_for_the_module__1.php
index b3b0b6d..63553d5 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__14.txt
+++ b/tests/__snapshots__/files/QueryWizardMakeCommandTest__it_generates__eloquent__query_wizard_for_the_module__1.php
@@ -1,16 +1,16 @@
+ * @return array
*/
protected function allowedAppends(): array
{
@@ -18,7 +18,7 @@ protected function allowedAppends(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultAppends(): array
{
@@ -26,7 +26,7 @@ protected function defaultAppends(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedFields(): array
{
@@ -36,7 +36,7 @@ protected function allowedFields(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedFilters(): array
{
@@ -44,7 +44,7 @@ protected function allowedFilters(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedIncludes(): array
{
@@ -52,7 +52,7 @@ protected function allowedIncludes(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultIncludes(): array
{
@@ -60,7 +60,7 @@ protected function defaultIncludes(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedSorts(): array
{
@@ -68,7 +68,7 @@ protected function allowedSorts(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultSorts(): array
{
diff --git a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__13.txt b/tests/__snapshots__/files/QueryWizardMakeCommandTest__it_generates__model__query_wizard_for_the_module__1.php
similarity index 62%
rename from tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__13.txt
rename to tests/__snapshots__/files/QueryWizardMakeCommandTest__it_generates__model__query_wizard_for_the_module__1.php
index a2fccb5..3a876bd 100644
--- a/tests/Commands/Generators/__snapshots__/ComponentsMakeCommandTest__it_generates_module_components__13.txt
+++ b/tests/__snapshots__/files/QueryWizardMakeCommandTest__it_generates__model__query_wizard_for_the_module__1.php
@@ -1,14 +1,14 @@
+ * @return array
*/
protected function allowedAppends(): array
{
@@ -16,7 +16,7 @@ protected function allowedAppends(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultAppends(): array
{
@@ -24,7 +24,7 @@ protected function defaultAppends(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedFields(): array
{
@@ -34,7 +34,7 @@ protected function allowedFields(): array
}
/**
- * @return array
+ * @return array
*/
protected function allowedIncludes(): array
{
@@ -42,7 +42,7 @@ protected function allowedIncludes(): array
}
/**
- * @return array
+ * @return array
*/
protected function defaultIncludes(): array
{
diff --git a/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__create__api_request_for_the_module__1.php b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__create__api_request_for_the_module__1.php
new file mode 100644
index 0000000..c17fe79
--- /dev/null
+++ b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__create__api_request_for_the_module__1.php
@@ -0,0 +1,28 @@
+validated());
+ }
+}
diff --git a/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__create__web_request_for_the_module__1.php b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__create__web_request_for_the_module__1.php
new file mode 100644
index 0000000..80d4521
--- /dev/null
+++ b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__create__web_request_for_the_module__1.php
@@ -0,0 +1,28 @@
+validated());
+ }
+}
diff --git a/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__delete__api_request_for_the_module__1.php b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__delete__api_request_for_the_module__1.php
new file mode 100644
index 0000000..d382341
--- /dev/null
+++ b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__delete__api_request_for_the_module__1.php
@@ -0,0 +1,20 @@
+route('author');
+ return $author && Gate::check('delete', $author);
+ }
+}
diff --git a/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__delete__web_request_for_the_module__1.php b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__delete__web_request_for_the_module__1.php
new file mode 100644
index 0000000..057de9f
--- /dev/null
+++ b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__delete__web_request_for_the_module__1.php
@@ -0,0 +1,20 @@
+route('author');
+ return $author && Gate::check('delete', $author);
+ }
+}
diff --git a/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__list__api_request_for_the_module__1.php b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__list__api_request_for_the_module__1.php
new file mode 100644
index 0000000..db74862
--- /dev/null
+++ b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__list__api_request_for_the_module__1.php
@@ -0,0 +1,20 @@
+route('author');
+ return $author && Gate::check('update', $author);
+ }
+
+ public function toDTO(): UpdateAuthorDTO
+ {
+ return UpdateAuthorDTO::from($this->validated());
+ }
+}
diff --git a/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__update__web_request_for_the_module__1.php b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__update__web_request_for_the_module__1.php
new file mode 100644
index 0000000..4e6f3b3
--- /dev/null
+++ b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__update__web_request_for_the_module__1.php
@@ -0,0 +1,28 @@
+route('author');
+ return $author && Gate::check('update', $author);
+ }
+
+ public function toDTO(): UpdateAuthorDTO
+ {
+ return UpdateAuthorDTO::from($this->validated());
+ }
+}
diff --git a/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__view__api_request_for_the_module__1.php b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__view__api_request_for_the_module__1.php
new file mode 100644
index 0000000..3131436
--- /dev/null
+++ b/tests/__snapshots__/files/RequestMakeCommandTest__it_generates__view__api_request_for_the_module__1.php
@@ -0,0 +1,20 @@
+route('author');
+ return $author && Gate::check('view', $author);
+ }
+}
diff --git a/tests/__snapshots__/files/ResourceMakeCommandTest__it_generates__collection__resource_for_the_module__1.php b/tests/__snapshots__/files/ResourceMakeCommandTest__it_generates__collection__resource_for_the_module__1.php
new file mode 100644
index 0000000..66593f2
--- /dev/null
+++ b/tests/__snapshots__/files/ResourceMakeCommandTest__it_generates__collection__resource_for_the_module__1.php
@@ -0,0 +1,17 @@
+name('api.authors.delete');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__delete__web_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__delete__web_route_for_the_module__1.php
new file mode 100644
index 0000000..951f87e
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__delete__web_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('web.authors.delete');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__get__api_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__get__api_route_for_the_module__1.php
new file mode 100644
index 0000000..e38cc25
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__get__api_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('web.authors.list');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__get__web_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__get__web_route_for_the_module__1.php
new file mode 100644
index 0000000..e38cc25
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__get__web_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('web.authors.list');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__options__api_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__options__api_route_for_the_module__1.php
new file mode 100644
index 0000000..5369614
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__options__api_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('api.authors.options');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__options__web_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__options__web_route_for_the_module__1.php
new file mode 100644
index 0000000..5dd3e59
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__options__web_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('web.authors.options');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__patch__api_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__patch__api_route_for_the_module__1.php
new file mode 100644
index 0000000..640858f
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__patch__api_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('api.authors.update');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__patch__web_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__patch__web_route_for_the_module__1.php
new file mode 100644
index 0000000..fda74ad
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__patch__web_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('web.authors.update');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__post__api_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__post__api_route_for_the_module__1.php
new file mode 100644
index 0000000..57b2069
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__post__api_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('api.authors.create');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__post__web_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__post__web_route_for_the_module__1.php
new file mode 100644
index 0000000..e031af6
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__post__web_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('web.authors.create');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__put__api_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__put__api_route_for_the_module__1.php
new file mode 100644
index 0000000..dcd1387
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__put__api_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('api.authors.update');
diff --git a/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__put__web_route_for_the_module__1.php b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__put__web_route_for_the_module__1.php
new file mode 100644
index 0000000..34f88ba
--- /dev/null
+++ b/tests/__snapshots__/files/RouteMakeCommandTest__it_generates__put__web_route_for_the_module__1.php
@@ -0,0 +1,7 @@
+name('web.authors.update');
diff --git a/tests/__snapshots__/files/RuleMakeCommandTest__it_generates_rule_for_the_module__1.php b/tests/__snapshots__/files/RuleMakeCommandTest__it_generates_rule_for_the_module__1.php
new file mode 100644
index 0000000..069e26b
--- /dev/null
+++ b/tests/__snapshots__/files/RuleMakeCommandTest__it_generates_rule_for_the_module__1.php
@@ -0,0 +1,19 @@
+handle(new CreatePermissionDTO(
+ name: 'view-author',
+ display_name: 'View any "authors"',
+ group: 'authors'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'create-author',
+ display_name: 'Create "authors"',
+ group: 'authors'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'update-author',
+ display_name: 'Update any "authors"',
+ group: 'authors'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'delete-author',
+ display_name: 'Delete any "authors"',
+ group: 'authors'
+ ));
+
+ $createPermissionAction->handle(new CreatePermissionDTO(
+ name: 'force-delete-author',
+ display_name: 'Force delete any "authors"',
+ group: 'authors'
+ ));
+ }
+}
diff --git a/tests/__snapshots__/files/SeederMakeCommandTest__it_generates__plain__seeder_for_the_module__1.php b/tests/__snapshots__/files/SeederMakeCommandTest__it_generates__plain__seeder_for_the_module__1.php
new file mode 100644
index 0000000..835b293
--- /dev/null
+++ b/tests/__snapshots__/files/SeederMakeCommandTest__it_generates__plain__seeder_for_the_module__1.php
@@ -0,0 +1,13 @@
+ 'create-author',
+ 'roles' => '',
+ ];
+
+ public function test_create_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $data = $this->getTestData();
+
+ $this->postJson(route('api.authors.create'), $data)
+ ->assertCreated()
+ ->assertJson(fn (AssertableJson $json) =>
+ $json->has('data', fn (AssertableJson $json) =>
+ $json->has('id')
+ ->whereAll($data)
+ ->etc()
+ )
+ );
+
+ $this->assertDatabaseHas(Author::class, $data);
+ }
+
+ public function test_create_author_with_invalid_data(): void
+ {
+ $this->actingAsTestUser();
+
+ $this->postJson(route('api.authors.create'), [])
+ ->assertUnprocessable()
+ ->assertJsonValidationErrors([
+ // TODO: add expected validation errors here
+ ]);
+ }
+
+ public function test_create_author_unauthenticated(): void
+ {
+ $data = $this->getTestData();
+
+ $this->postJson(route('api.authors.create'), $data)
+ ->assertUnauthorized();
+ }
+
+ public function test_create_author_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $data = $this->getTestData();
+
+ $this->postJson(route('api.authors.create'), $data)
+ ->assertForbidden();
+ }
+
+ protected function getTestData(array $mergeData = []): array
+ {
+ return array_merge([
+ // TODO: add fields here
+ ], $mergeData);
+ }
+}
diff --git a/tests/__snapshots__/files/TestMakeCommandTest__it_generates_create__web__test_for_the_module__1.php b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_create__web__test_for_the_module__1.php
new file mode 100644
index 0000000..9fdcca6
--- /dev/null
+++ b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_create__web__test_for_the_module__1.php
@@ -0,0 +1,50 @@
+ 'create-author',
+ 'roles' => '',
+ ];
+
+ protected function getTestData(array $mergeData = []): array
+ {
+ return array_merge([
+ // TODO: add fields here
+ ], $mergeData);
+ }
+
+ public function test_create_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $data = $this->getTestData();
+
+ $this->post(route('web.authors.create'), $data)
+ ->assertCreated();
+
+ $this->assertDatabaseHas(Author::class, $data);
+ }
+
+ public function test_create_author_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $data = $this->getTestData();
+
+ $this->post(route('web.authors.create'), $data)
+ ->assertForbidden();
+ }
+}
diff --git a/tests/__snapshots__/files/TestMakeCommandTest__it_generates_delete__api__test_for_the_module__1.php b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_delete__api__test_for_the_module__1.php
new file mode 100644
index 0000000..eb267f3
--- /dev/null
+++ b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_delete__api__test_for_the_module__1.php
@@ -0,0 +1,62 @@
+ 'delete-author',
+ 'roles' => '',
+ ];
+
+ public function test_delete_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $author = Author::factory()->create();
+
+ $this->deleteJson(route('api.authors.delete', ['author' => $author->getKey()]))
+ ->assertNoContent();
+
+ $this->assertNull(Author::find($author->getKey()));
+ }
+
+ public function test_delete_author_unauthenticated(): void
+ {
+ $author = Author::factory()->create();
+
+ $this->deleteJson(route('api.authors.delete', ['author' => $author->getKey()]))
+ ->assertUnauthorized();
+ }
+
+ public function test_delete_author_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $author = Author::factory()->create();
+
+ $this->deleteJson(route('api.authors.delete', ['author' => $author->getKey()]))
+ ->assertForbidden();
+ }
+
+ public function test_delete_not_existing_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $this->deleteJson(route('api.authors.delete', ['author' => 7777]))
+ ->assertNotFound();
+ }
+}
diff --git a/tests/__snapshots__/files/TestMakeCommandTest__it_generates_delete__web__test_for_the_module__1.php b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_delete__web__test_for_the_module__1.php
new file mode 100644
index 0000000..e5783a9
--- /dev/null
+++ b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_delete__web__test_for_the_module__1.php
@@ -0,0 +1,51 @@
+ 'delete-author',
+ 'roles' => '',
+ ];
+
+ public function test_delete_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $author = Author::factory()->create();
+
+ $this->delete(route('web.authors.delete', ['author' => $author->getKey()]))
+ ->assertNoContent();
+
+ $this->assertNull(Author::find($author->getKey()));
+ }
+
+ public function test_delete_author_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $author = Author::factory()->create();
+
+ $this->delete(route('web.authors.delete', ['author' => $author->getKey()]))
+ ->assertForbidden();
+ }
+
+ public function test_delete_not_existing_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $this->delete(route('web.authors.delete', ['author' => 7777]))
+ ->assertNotFound();
+ }
+}
diff --git a/tests/__snapshots__/files/TestMakeCommandTest__it_generates_list__api__test_for_the_module__1.php b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_list__api__test_for_the_module__1.php
new file mode 100644
index 0000000..9ac136a
--- /dev/null
+++ b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_list__api__test_for_the_module__1.php
@@ -0,0 +1,58 @@
+ 'view-author',
+ 'roles' => '',
+ ];
+
+ public function test_list_authors(): void
+ {
+ $this->actingAsTestUser();
+
+ Author::factory()->count(3)->create();
+
+ $this->getJson(route('api.authors.list'))
+ ->assertOk()
+ ->assertJsonStructure([
+ 'links',
+ 'meta',
+ 'data'
+ ])
+ ->assertJsonCount(3, 'data');
+ }
+
+ public function test_list_authors_unauthenticated(): void
+ {
+ Author::factory()->count(3)->create();
+
+ $this->getJson(route('api.authors.list'))
+ ->assertUnauthorized();
+ }
+
+ public function test_list_authors_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ Author::factory()->count(3)->create();
+
+ $this->getJson(route('api.authors.list'))
+ ->assertForbidden();
+ }
+}
diff --git a/tests/__snapshots__/files/TestMakeCommandTest__it_generates_plain__api__test_for_the_module__1.php b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_plain__api__test_for_the_module__1.php
new file mode 100644
index 0000000..2eddedd
--- /dev/null
+++ b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_plain__api__test_for_the_module__1.php
@@ -0,0 +1,28 @@
+ '',
+ 'roles' => '',
+ ];
+
+ public function test(): void
+ {
+ //
+ }
+}
diff --git a/tests/__snapshots__/files/TestMakeCommandTest__it_generates_plain__cli__test_for_the_module__1.php b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_plain__cli__test_for_the_module__1.php
new file mode 100644
index 0000000..0b8a895
--- /dev/null
+++ b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_plain__cli__test_for_the_module__1.php
@@ -0,0 +1,17 @@
+ 'update-author',
+ 'roles' => '',
+ ];
+
+ public function test_update_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $author = Author::factory()->create();
+
+ $data = $this->getTestData();
+ $expectedData = array_merge($data, [
+ 'id' => $author->getKey(),
+ ]);
+
+ $this->patchJson(route('api.authors.update', ['author' => $author->getKey()]), $data)
+ ->assertOk()
+ ->assertJson(fn (AssertableJson $json) =>
+ $json->has('data', fn (AssertableJson $json) =>
+ $json->whereAll($expectedData)
+ ->etc()
+ )
+ );
+
+ $this->assertDatabaseHas(Author::class, $expectedData);
+ }
+
+ public function test_update_author_with_invalid_data(): void
+ {
+ $this->actingAsTestUser();
+
+ $author = Author::factory()->create();
+
+ $this->patchJson(route('api.authors.update', ['author' => $author->getKey()]), [])
+ ->assertUnprocessable()
+ ->assertJsonValidationErrors([
+ // TODO: add expected validation errors here
+ ]);
+ }
+
+ public function test_update_author_unauthenticated(): void
+ {
+ $author = Author::factory()->create();
+
+ $data = $this->getTestData();
+
+ $this->patchJson(route('api.authors.update', ['author' => $author->getKey()]), $data)
+ ->assertUnauthorized();
+ }
+
+ public function test_update_author_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $author = Author::factory()->create();
+
+ $data = $this->getTestData();
+
+ $this->patchJson(route('api.authors.update', ['author' => $author->getKey()]), $data)
+ ->assertForbidden();
+ }
+
+ public function test_update_non_existing_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $data = $this->getTestData();
+
+ $this->patchJson(route('api.authors.update', ['author' => 7777]), $data)
+ ->assertNotFound();
+ }
+
+ protected function getTestData(array $mergeData = []): array
+ {
+ return array_merge([
+ // TODO: add fields here
+ ], $mergeData);
+ }
+}
diff --git a/tests/__snapshots__/files/TestMakeCommandTest__it_generates_update__web__test_for_the_module__1.php b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_update__web__test_for_the_module__1.php
new file mode 100644
index 0000000..8d6b05d
--- /dev/null
+++ b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_update__web__test_for_the_module__1.php
@@ -0,0 +1,67 @@
+ 'update-author',
+ 'roles' => '',
+ ];
+
+ protected function getTestData(array $mergeData = []): array
+ {
+ return array_merge([
+ // TODO: add fields here
+ ], $mergeData);
+ }
+
+ public function test_update_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $author = Author::factory()->create();
+
+ $data = $this->getTestData();
+ $expectedData = array_merge($data, [
+ 'id' => $author->getKey(),
+ ]);
+
+ $this->patch(route('web.authors.update', ['author' => $author->getKey()]), $data)
+ ->assertOk();
+
+ $this->assertDatabaseHas(Author::class, $expectedData);
+ }
+
+ public function test_update_author_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $author = Author::factory()->create();
+
+ $data = $this->getTestData();
+
+ $this->patch(route('web.authors.update', ['author' => $author->getKey()]), $data)
+ ->assertForbidden();
+ }
+
+ public function test_update_non_existing_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $data = $this->getTestData();
+
+ $this->patch(route('web.authors.update', ['author' => 7777]), $data)
+ ->assertNotFound();
+ }
+}
diff --git a/tests/__snapshots__/files/TestMakeCommandTest__it_generates_view__api__test_for_the_module__1.php b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_view__api__test_for_the_module__1.php
new file mode 100644
index 0000000..7914dcc
--- /dev/null
+++ b/tests/__snapshots__/files/TestMakeCommandTest__it_generates_view__api__test_for_the_module__1.php
@@ -0,0 +1,68 @@
+ 'view-author',
+ 'roles' => '',
+ ];
+
+ public function test_view_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $author = Author::factory()->create();
+ $expectedData = $author->toArray();
+
+ $this->getJson(route('api.authors.view', ['author' => $author->getKey()]))
+ ->assertOk()
+ ->assertJson(fn (AssertableJson $json) =>
+ $json->has('data', fn (AssertableJson $json) =>
+ $json->whereAll($expectedData)
+ ->etc()
+ )
+ );
+ }
+
+ public function test_view_author_unauthenticated(): void
+ {
+ $author = Author::factory()->create();
+
+ $this->getJson(route('api.authors.view', ['author' => $author->getKey()]))
+ ->assertUnauthorized();
+ }
+
+ public function test_view_author_without_access(): void
+ {
+ $this->actingAsTestUserWithoutAccess();
+
+ $author = Author::factory()->create();
+
+ $this->getJson(route('api.authors.view', ['author' => $author->getKey()]))
+ ->assertForbidden();
+ }
+
+ public function test_view_not_existing_author(): void
+ {
+ $this->actingAsTestUser();
+
+ $this->getJson(route('api.authors.view', ['author' => 7777]))
+ ->assertNotFound();
+ }
+}
diff --git a/tests/fixtures/laravel/.gitignore b/tests/fixtures/laravel/.gitignore
index cba67f7..8d29ab4 100644
--- a/tests/fixtures/laravel/.gitignore
+++ b/tests/fixtures/laravel/.gitignore
@@ -1,2 +1,2 @@
-app/Modules
-modules_statuses.json
+modules
+vendor
diff --git a/tests/fixtures/laravel/app/Console/.gitkeep b/tests/fixtures/laravel/app/Console/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/laravel/app/Exceptions/.gitkeep b/tests/fixtures/laravel/app/Exceptions/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/laravel/app/Http/Controllers/.gitkeep b/tests/fixtures/laravel/app/Http/Controllers/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/laravel/app/Http/Middleware/.gitkeep b/tests/fixtures/laravel/app/Http/Middleware/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/laravel/app/Models/.gitkeep b/tests/fixtures/laravel/app/Models/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/laravel/app/Providers/.gitkeep b/tests/fixtures/laravel/app/Providers/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/laravel/bootstrap/app.php b/tests/fixtures/laravel/bootstrap/app.php
index f7f1d2c..151dd2e 100644
--- a/tests/fixtures/laravel/bootstrap/app.php
+++ b/tests/fixtures/laravel/bootstrap/app.php
@@ -3,7 +3,7 @@
use Orchestra\Testbench\Console\Commander;
$APP_KEY = $_SERVER['APP_KEY'] ?? $_ENV['APP_KEY'] ?? 'AckfSECXIvnK5r28GVIWUAxmbBSjTsmF';
-$DB_CONNECTION = $_SERVER['DB_CONNECTION'] ?? $_ENV['DB_CONNECTION'] ?? 'testing';
+$DB_CONNECTION = $_SERVER['DB_CONNECTION'] ?? $_ENV['DB_CONNECTION'] ?? 'testing';
$config = ['env' => ['APP_KEY="'.$APP_KEY.'"', 'DB_CONNECTION="'.$DB_CONNECTION.'"'], 'providers' => []];
diff --git a/tests/fixtures/laravel/composer.json b/tests/fixtures/laravel/composer.json
index 03d8029..1977705 100644
--- a/tests/fixtures/laravel/composer.json
+++ b/tests/fixtures/laravel/composer.json
@@ -11,37 +11,35 @@
],
"license": "MIT",
"require": {
- "php": "^8.0",
- "laravel/framework": "^8.55",
- "wikimedia/composer-merge-plugin": "^2.0.1"
+ "php": "^8.1",
+ "laravel/framework": "^10.0"
},
"require-dev": {
- "phpunit/phpunit": "^9.5.2"
+ "phpunit/phpunit": "^10.5.9"
},
"autoload": {
"classmap": [
- "database",
- "tests/TestCase.php"
+ "database"
],
"psr-4": {
- "App\\": "app/"
+ "App\\": "app/",
+ "Modules\\": "modules/"
}
},
"extra": {
"laravel": {
"dont-discover": []
- },
- "merge-plugin": {
- "include": [
- "app/Modules/*/composer.json"
- ],
- "recurse": true,
- "replace": false,
- "merge-dev": true,
- "merge-extra": false,
- "merge-extra-deep": false,
- "merge-scripts": true
}
},
- "minimum-stability": "dev"
+ "config": {
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true,
+ "allow-plugins": {
+ "pestphp/pest-plugin": true,
+ "php-http/discovery": true
+ }
+ },
+ "minimum-stability": "stable",
+ "prefer-stable": true
}
diff --git a/tests/fixtures/stubs/InvalidJsonModule/module.json b/tests/fixtures/stubs/InvalidJsonModule/module.json
deleted file mode 100644
index 916aa9b..0000000
--- a/tests/fixtures/stubs/InvalidJsonModule/module.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- a: 1
-}
diff --git a/tests/fixtures/stubs/modules/invalid/without-name/composer.json b/tests/fixtures/stubs/modules/invalid/without-name/composer.json
new file mode 100644
index 0000000..0906c69
--- /dev/null
+++ b/tests/fixtures/stubs/modules/invalid/without-name/composer.json
@@ -0,0 +1,20 @@
+{
+ "name": "",
+ "description": "Invalid module without name",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\WithoutName\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\WithoutName\\Tests\\": "tests/"
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/invalid/without-namespace/composer.json b/tests/fixtures/stubs/modules/invalid/without-namespace/composer.json
new file mode 100644
index 0000000..9b65e62
--- /dev/null
+++ b/tests/fixtures/stubs/modules/invalid/without-namespace/composer.json
@@ -0,0 +1,10 @@
+{
+ "name": "laraneat/without-namespace",
+ "description": "Invalid module without namespace",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ]
+}
diff --git a/tests/fixtures/stubs/modules/valid/article-category/composer.json b/tests/fixtures/stubs/modules/valid/article-category/composer.json
new file mode 100644
index 0000000..792a48f
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/article-category/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "laraneat/article-category",
+ "description": "ArticleCategory module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\ArticleCategory\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\ArticleCategory\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\ArticleCategory\\Providers\\ArticleCategoryServiceProvider",
+ "Modules\\ArticleCategory\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": []
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/article-category/src/Providers/ArticleCategoryServiceProvider.php b/tests/fixtures/stubs/modules/valid/article-category/src/Providers/ArticleCategoryServiceProvider.php
new file mode 100644
index 0000000..a845107
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/article-category/src/Providers/ArticleCategoryServiceProvider.php
@@ -0,0 +1,89 @@
+loadMigrations();
+ // $this->loadTranslations();
+ // $this->loadCommands();
+ // $this->loadViews();
+ }
+
+ /**
+ * Register translations.
+ */
+ public function loadTranslations(): void
+ {
+ $sourcePath = realpath('../../lang');
+ $langPath = $this->app->langPath('modules/' . $this->modulePackageName);
+
+ $this->loadTranslationsFrom($sourcePath, $this->modulePackageName);
+
+ $this->publishes([
+ $sourcePath => $langPath,
+ ], 'article-category-translations');
+ }
+
+ /**
+ * Register views.
+ */
+ public function loadViews(): void
+ {
+ $sourcePath = realpath('../../resources/views');
+ $viewsPath = $this->app->resourcePath('views/modules/' . $this->modulePackageName);
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths($this->modulePackageName), [$sourcePath]),
+ $this->modulePackageName
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath,
+ ], 'article-category-views');
+ }
+
+ /**
+ * Register migrations.
+ */
+ public function loadMigrations(): void
+ {
+ $sourcePath = realpath('../../database/migrations');
+ $migrationsPath = $this->app->databasePath('migrations');
+
+ $this->loadMigrationsFrom($sourcePath);
+
+ $this->publishes([
+ $sourcePath => $migrationsPath,
+ ], 'article-category-migrations');
+ }
+
+ /**
+ * Register artisan commands.
+ */
+ public function loadCommands(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ 'Modules\\ArticleCategory\\UI\\CLI\\Commands' => __DIR__.'/../UI/CLI/Commands',
+ ]);
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/article-category/src/Providers/RouteServiceProvider.php b/tests/fixtures/stubs/modules/valid/article-category/src/Providers/RouteServiceProvider.php
new file mode 100644
index 0000000..8cfa02b
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/article-category/src/Providers/RouteServiceProvider.php
@@ -0,0 +1,57 @@
+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('Modules\\ArticleCategory\\UI\\WEB\\Controllers')
+ ->group(function () {
+ $this->loadRoutesFromDirectory(realpath('../UI/WEB/routes'));
+ });
+ }
+
+ /**
+ * Define the "api" routes for the application.
+ * These routes are typically stateless.
+ */
+ protected function mapApiRoutes(): void
+ {
+ Route::prefix('api')
+ ->middleware('api')
+ // ->namespace('Modules\\ArticleCategory\\UI\\API\\Controllers')
+ ->group(function () {
+ $this->loadRoutesFromDirectory(realpath('../UI/API/routes'));
+ });
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/article-copy/composer.json b/tests/fixtures/stubs/modules/valid/article-copy/composer.json
new file mode 100644
index 0000000..02d9b7b
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/article-copy/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "laraneat/article",
+ "description": "Article module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Article\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Article\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Article\\Providers\\ArticleServiceProvider",
+ "Modules\\Article\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": []
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/article-copy/src/Providers/ArticleServiceProvider.php b/tests/fixtures/stubs/modules/valid/article-copy/src/Providers/ArticleServiceProvider.php
new file mode 100644
index 0000000..48ccbe3
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/article-copy/src/Providers/ArticleServiceProvider.php
@@ -0,0 +1,89 @@
+loadMigrations();
+ // $this->loadTranslations();
+ // $this->loadCommands();
+ // $this->loadViews();
+ }
+
+ /**
+ * Register translations.
+ */
+ public function loadTranslations(): void
+ {
+ $sourcePath = realpath('../../lang');
+ $langPath = $this->app->langPath('modules/' . $this->modulePackageName);
+
+ $this->loadTranslationsFrom($sourcePath, $this->modulePackageName);
+
+ $this->publishes([
+ $sourcePath => $langPath,
+ ], 'article-translations');
+ }
+
+ /**
+ * Register views.
+ */
+ public function loadViews(): void
+ {
+ $sourcePath = realpath('../../resources/views');
+ $viewsPath = $this->app->resourcePath('views/modules/' . $this->modulePackageName);
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths($this->modulePackageName), [$sourcePath]),
+ $this->modulePackageName
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath,
+ ], 'article-views');
+ }
+
+ /**
+ * Register migrations.
+ */
+ public function loadMigrations(): void
+ {
+ $sourcePath = realpath('../../database/migrations');
+ $migrationsPath = $this->app->databasePath('migrations');
+
+ $this->loadMigrationsFrom($sourcePath);
+
+ $this->publishes([
+ $sourcePath => $migrationsPath,
+ ], 'article-migrations');
+ }
+
+ /**
+ * Register artisan commands.
+ */
+ public function loadCommands(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ 'Modules\\Article\\UI\\CLI\\Commands' => __DIR__.'/../UI/CLI/Commands',
+ ]);
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/article-copy/src/Providers/RouteServiceProvider.php b/tests/fixtures/stubs/modules/valid/article-copy/src/Providers/RouteServiceProvider.php
new file mode 100644
index 0000000..e20139c
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/article-copy/src/Providers/RouteServiceProvider.php
@@ -0,0 +1,57 @@
+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('Modules\\Article\\UI\\WEB\\Controllers')
+ ->group(function () {
+ $this->loadRoutesFromDirectory(realpath('../UI/WEB/routes'));
+ });
+ }
+
+ /**
+ * Define the "api" routes for the application.
+ * These routes are typically stateless.
+ */
+ protected function mapApiRoutes(): void
+ {
+ Route::prefix('api')
+ ->middleware('api')
+ // ->namespace('Modules\\Article\\UI\\API\\Controllers')
+ ->group(function () {
+ $this->loadRoutesFromDirectory(realpath('../UI/API/routes'));
+ });
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/article/composer.json b/tests/fixtures/stubs/modules/valid/article/composer.json
new file mode 100644
index 0000000..02d9b7b
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/article/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "laraneat/article",
+ "description": "Article module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Article\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Article\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Article\\Providers\\ArticleServiceProvider",
+ "Modules\\Article\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": []
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/article/src/Providers/ArticleServiceProvider.php b/tests/fixtures/stubs/modules/valid/article/src/Providers/ArticleServiceProvider.php
new file mode 100644
index 0000000..48ccbe3
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/article/src/Providers/ArticleServiceProvider.php
@@ -0,0 +1,89 @@
+loadMigrations();
+ // $this->loadTranslations();
+ // $this->loadCommands();
+ // $this->loadViews();
+ }
+
+ /**
+ * Register translations.
+ */
+ public function loadTranslations(): void
+ {
+ $sourcePath = realpath('../../lang');
+ $langPath = $this->app->langPath('modules/' . $this->modulePackageName);
+
+ $this->loadTranslationsFrom($sourcePath, $this->modulePackageName);
+
+ $this->publishes([
+ $sourcePath => $langPath,
+ ], 'article-translations');
+ }
+
+ /**
+ * Register views.
+ */
+ public function loadViews(): void
+ {
+ $sourcePath = realpath('../../resources/views');
+ $viewsPath = $this->app->resourcePath('views/modules/' . $this->modulePackageName);
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths($this->modulePackageName), [$sourcePath]),
+ $this->modulePackageName
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath,
+ ], 'article-views');
+ }
+
+ /**
+ * Register migrations.
+ */
+ public function loadMigrations(): void
+ {
+ $sourcePath = realpath('../../database/migrations');
+ $migrationsPath = $this->app->databasePath('migrations');
+
+ $this->loadMigrationsFrom($sourcePath);
+
+ $this->publishes([
+ $sourcePath => $migrationsPath,
+ ], 'article-migrations');
+ }
+
+ /**
+ * Register artisan commands.
+ */
+ public function loadCommands(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ 'Modules\\Article\\UI\\CLI\\Commands' => __DIR__.'/../UI/CLI/Commands',
+ ]);
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/article/src/Providers/RouteServiceProvider.php b/tests/fixtures/stubs/modules/valid/article/src/Providers/RouteServiceProvider.php
new file mode 100644
index 0000000..e20139c
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/article/src/Providers/RouteServiceProvider.php
@@ -0,0 +1,57 @@
+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('Modules\\Article\\UI\\WEB\\Controllers')
+ ->group(function () {
+ $this->loadRoutesFromDirectory(realpath('../UI/WEB/routes'));
+ });
+ }
+
+ /**
+ * Define the "api" routes for the application.
+ * These routes are typically stateless.
+ */
+ protected function mapApiRoutes(): void
+ {
+ Route::prefix('api')
+ ->middleware('api')
+ // ->namespace('Modules\\Article\\UI\\API\\Controllers')
+ ->group(function () {
+ $this->loadRoutesFromDirectory(realpath('../UI/API/routes'));
+ });
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/author/composer.json b/tests/fixtures/stubs/modules/valid/author/composer.json
new file mode 100644
index 0000000..da14fd9
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/author/composer.json
@@ -0,0 +1,31 @@
+{
+ "name": "laraneat/author",
+ "description": "Author module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Author\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\Author\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\Author\\Providers\\AuthorServiceProvider",
+ "Modules\\Author\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": {
+ "AuthorFacade": "Modules\\Author\\Facades\\SomeFacade"
+ }
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/author/src/Facades/SomeFacade.php b/tests/fixtures/stubs/modules/valid/author/src/Facades/SomeFacade.php
new file mode 100644
index 0000000..bee9723
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/author/src/Facades/SomeFacade.php
@@ -0,0 +1,7 @@
+loadMigrations();
+ // $this->loadTranslations();
+ // $this->loadCommands();
+ // $this->loadViews();
+ }
+
+ /**
+ * Register translations.
+ */
+ public function loadTranslations(): void
+ {
+ $sourcePath = realpath('../../lang');
+ $langPath = $this->app->langPath('modules/' . $this->modulePackageName);
+
+ $this->loadTranslationsFrom($sourcePath, $this->modulePackageName);
+
+ $this->publishes([
+ $sourcePath => $langPath,
+ ], 'author-translations');
+ }
+
+ /**
+ * Register views.
+ */
+ public function loadViews(): void
+ {
+ $sourcePath = realpath('../../resources/views');
+ $viewsPath = $this->app->resourcePath('views/modules/' . $this->modulePackageName);
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths($this->modulePackageName), [$sourcePath]),
+ $this->modulePackageName
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath,
+ ], 'author-views');
+ }
+
+ /**
+ * Register migrations.
+ */
+ public function loadMigrations(): void
+ {
+ $sourcePath = realpath('../../database/migrations');
+ $migrationsPath = $this->app->databasePath('migrations');
+
+ $this->loadMigrationsFrom($sourcePath);
+
+ $this->publishes([
+ $sourcePath => $migrationsPath,
+ ], 'author-migrations');
+ }
+
+ /**
+ * Register artisan commands.
+ */
+ public function loadCommands(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ 'Modules\\Author\\UI\\CLI\\Commands' => __DIR__.'/../UI/CLI/Commands',
+ ]);
+ }
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__14.txt b/tests/fixtures/stubs/modules/valid/author/src/Providers/RouteServiceProvider.php
similarity index 63%
rename from tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__14.txt
rename to tests/fixtures/stubs/modules/valid/author/src/Providers/RouteServiceProvider.php
index 3d39542..a9eff6d 100644
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_can_set_custom_model__14.txt
+++ b/tests/fixtures/stubs/modules/valid/author/src/Providers/RouteServiceProvider.php
@@ -1,16 +1,16 @@
namespace('App\\Modules\\Blog\\UI\\WEB\\Controllers')
+ // ->namespace('Modules\\Author\\UI\\WEB\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/WEB/Routes'));
+ $this->loadRoutesFromDirectory(realpath('../UI/WEB/Routes'));
});
}
@@ -51,9 +51,9 @@ protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
-// ->namespace('App\\Modules\\Blog\\UI\\API\\Controllers')
+ // ->namespace('Modules\\Author\\UI\\API\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/API/Routes'));
+ $this->loadRoutesFromDirectory(realpath('../UI/API/Routes'));
});
}
}
diff --git a/tests/fixtures/stubs/modules/valid/empty-module/composer.json b/tests/fixtures/stubs/modules/valid/empty-module/composer.json
new file mode 100644
index 0000000..be56de9
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/empty-module/composer.json
@@ -0,0 +1,15 @@
+{
+ "name": "laraneat/empty",
+ "description": "Empty module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\Empty\\": "src/"
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/empty/composer.json b/tests/fixtures/stubs/modules/valid/empty/composer.json
new file mode 100644
index 0000000..f8d6492
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/empty/composer.json
@@ -0,0 +1,15 @@
+{
+ "name": "empty/empty",
+ "description": "Empty module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Empty\\Empty\\": "src/"
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/navigation/composer.json b/tests/fixtures/stubs/modules/valid/navigation/composer.json
new file mode 100644
index 0000000..f27c35b
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/navigation/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "laraneat/location",
+ "description": "GeoLocation module for testing",
+ "authors": [
+ {
+ "name": "Salavat Salakhutdinov",
+ "email": "salahutdinov.salavat@gmail.com"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Modules\\GeoLocation\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Modules\\GeoLocation\\Tests\\": "tests/"
+ }
+ },
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Modules\\GeoLocation\\Providers\\GeoLocationServiceProvider",
+ "Modules\\GeoLocation\\Providers\\RouteServiceProvider"
+ ],
+ "aliases": []
+ }
+ }
+}
diff --git a/tests/fixtures/stubs/modules/valid/navigation/src/Providers/GeoLocationServiceProvider.php b/tests/fixtures/stubs/modules/valid/navigation/src/Providers/GeoLocationServiceProvider.php
new file mode 100644
index 0000000..979cd4c
--- /dev/null
+++ b/tests/fixtures/stubs/modules/valid/navigation/src/Providers/GeoLocationServiceProvider.php
@@ -0,0 +1,89 @@
+loadMigrations();
+ // $this->loadTranslations();
+ // $this->loadCommands();
+ // $this->loadViews();
+ }
+
+ /**
+ * Register translations.
+ */
+ public function loadTranslations(): void
+ {
+ $sourcePath = realpath('../../lang');
+ $langPath = $this->app->langPath('modules/' . $this->modulePackageName);
+
+ $this->loadTranslationsFrom($sourcePath, $this->modulePackageName);
+
+ $this->publishes([
+ $sourcePath => $langPath,
+ ], 'geo-location-translations');
+ }
+
+ /**
+ * Register views.
+ */
+ public function loadViews(): void
+ {
+ $sourcePath = realpath('../../resources/views');
+ $viewsPath = $this->app->resourcePath('views/modules/' . $this->modulePackageName);
+
+ $this->loadViewsFrom(
+ array_merge($this->getPublishableViewPaths($this->modulePackageName), [$sourcePath]),
+ $this->modulePackageName
+ );
+
+ $this->publishes([
+ $sourcePath => $viewsPath,
+ ], 'geo-location-views');
+ }
+
+ /**
+ * Register migrations.
+ */
+ public function loadMigrations(): void
+ {
+ $sourcePath = realpath('../../database/migrations');
+ $migrationsPath = $this->app->databasePath('migrations');
+
+ $this->loadMigrationsFrom($sourcePath);
+
+ $this->publishes([
+ $sourcePath => $migrationsPath,
+ ], 'geo-location-migrations');
+ }
+
+ /**
+ * Register artisan commands.
+ */
+ public function loadCommands(): void
+ {
+ if ($this->app->runningInConsole()) {
+ $this->loadCommandsFrom([
+ 'Modules\\GeoLocation\\UI\\CLI\\Commands' => __DIR__.'/../UI/CLI/Commands',
+ ]);
+ }
+ }
+}
diff --git a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__12.txt b/tests/fixtures/stubs/modules/valid/navigation/src/Providers/RouteServiceProvider.php
similarity index 64%
rename from tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__12.txt
rename to tests/fixtures/stubs/modules/valid/navigation/src/Providers/RouteServiceProvider.php
index 8e33d3a..7bbbe04 100644
--- a/tests/Commands/Generators/__snapshots__/ModuleMakeCommandTest__it_generates_module_components__12.txt
+++ b/tests/fixtures/stubs/modules/valid/navigation/src/Providers/RouteServiceProvider.php
@@ -1,16 +1,14 @@
namespace('App\\Modules\\Article\\UI\\WEB\\Controllers')
+ // ->namespace('Modules\\GeoLocation\\UI\\WEB\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/WEB/Routes'));
+ $this->loadRoutesFromDirectory(realpath('../UI/WEB/routes'));
});
}
@@ -51,9 +49,9 @@ protected function mapApiRoutes(): void
{
Route::prefix('api')
->middleware('api')
-// ->namespace('App\\Modules\\Article\\UI\\API\\Controllers')
+ // ->namespace('Modules\\GeoLocation\\UI\\API\\Controllers')
->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/API/Routes'));
+ $this->loadRoutesFromDirectory(realpath('../UI/API/routes'));
});
}
}
diff --git a/tests/fixtures/stubs/valid/Article/Actions/CreateArticleAction.php b/tests/fixtures/stubs/valid/Article/Actions/CreateArticleAction.php
deleted file mode 100644
index abbd705..0000000
--- a/tests/fixtures/stubs/valid/Article/Actions/CreateArticleAction.php
+++ /dev/null
@@ -1,37 +0,0 @@
-handle(
- //
- );
-
- return (new ArticleResource($article))->created();
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Actions/DeleteArticleAction.php b/tests/fixtures/stubs/valid/Article/Actions/DeleteArticleAction.php
deleted file mode 100644
index 2f15442..0000000
--- a/tests/fixtures/stubs/valid/Article/Actions/DeleteArticleAction.php
+++ /dev/null
@@ -1,34 +0,0 @@
-delete();
- }
-
- /**
- * @param DeleteArticleRequest $request
- * @param Article $article
- *
- * @return JsonResponse
- */
- public function asController(DeleteArticleRequest $request, Article $article): JsonResponse
- {
- $this->handle($article);
-
- return $this->noContent();
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Actions/ListArticlesAction.php b/tests/fixtures/stubs/valid/Article/Actions/ListArticlesAction.php
deleted file mode 100644
index 1796517..0000000
--- a/tests/fixtures/stubs/valid/Article/Actions/ListArticlesAction.php
+++ /dev/null
@@ -1,36 +0,0 @@
-build()
- ->jsonPaginate();
- }
-
- /**
- * @param ListArticlesRequest $request
- *
- * @return ResourceCollection
- */
- public function asController(ListArticlesRequest $request): ResourceCollection
- {
- return ArticleResource::collection($this->handle($request));
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Actions/UpdateArticleAction.php b/tests/fixtures/stubs/valid/Article/Actions/UpdateArticleAction.php
deleted file mode 100644
index b8d63ef..0000000
--- a/tests/fixtures/stubs/valid/Article/Actions/UpdateArticleAction.php
+++ /dev/null
@@ -1,46 +0,0 @@
-update($data);
-
- return $article;
- }
-
- /**
- * @param UpdateArticleRequest $request
- * @param Article $article
- *
- * @return ArticleResource
- */
- public function asController(UpdateArticleRequest $request, Article $article): ArticleResource
- {
- $sanitizedData = $request->sanitizeInput([
- //
- ]);
-
- $article = $this->handle($article, $sanitizedData);
-
- return new ArticleResource($article);
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Actions/ViewArticleAction.php b/tests/fixtures/stubs/valid/Article/Actions/ViewArticleAction.php
deleted file mode 100644
index d2965ff..0000000
--- a/tests/fixtures/stubs/valid/Article/Actions/ViewArticleAction.php
+++ /dev/null
@@ -1,35 +0,0 @@
-build();
- }
-
- /**
- * @param ViewArticleRequest $request
- * @param Article $article
- *
- * @return ArticleResource
- */
- public function asController(ViewArticleRequest $request, Article $article): ArticleResource
- {
- return new ArticleResource($this->handle($request, $article));
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Config/article-module.php b/tests/fixtures/stubs/valid/Article/Config/article-module.php
deleted file mode 100644
index 1faef3e..0000000
--- a/tests/fixtures/stubs/valid/Article/Config/article-module.php
+++ /dev/null
@@ -1,8 +0,0 @@
- 'Article',
- 'some' => [
- 'nested' => 'Hello world'
- ]
-];
diff --git a/tests/fixtures/stubs/valid/Article/Data/Factories/ArticleFactory.php b/tests/fixtures/stubs/valid/Article/Data/Factories/ArticleFactory.php
deleted file mode 100644
index 60c7559..0000000
--- a/tests/fixtures/stubs/valid/Article/Data/Factories/ArticleFactory.php
+++ /dev/null
@@ -1,36 +0,0 @@
-id();
-
- $table->timestamps();
- });
- }
-
- /**
- * Reverse the migrations.
- *
- * @return void
- */
- public function down()
- {
- Schema::dropIfExists('articles');
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Data/Seeders/ArticlePermissionsSeeder_1.php b/tests/fixtures/stubs/valid/Article/Data/Seeders/ArticlePermissionsSeeder_1.php
deleted file mode 100644
index 14ec389..0000000
--- a/tests/fixtures/stubs/valid/Article/Data/Seeders/ArticlePermissionsSeeder_1.php
+++ /dev/null
@@ -1,45 +0,0 @@
-handle(new CreatePermissionDTO(
- name: 'view-article',
- display_name: 'View any articles',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'create-article',
- display_name: 'Create articles',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'update-article',
- display_name: 'Update any articles',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'delete-article',
- display_name: 'Delete any articles',
- group: 'articles'
- ));
-
- $createPermissionAction->handle(new CreatePermissionDTO(
- name: 'force-delete-article',
- display_name: 'Force delete any articles',
- group: 'articles'
- ));
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Models/Article.php b/tests/fixtures/stubs/valid/Article/Models/Article.php
deleted file mode 100644
index 49b0ac2..0000000
--- a/tests/fixtures/stubs/valid/Article/Models/Article.php
+++ /dev/null
@@ -1,23 +0,0 @@
-can('view-article');
- }
-
- /**
- * Determine whether the user can view the model.
- *
- * @param User $user
- * @param Article $article
- * @return \Illuminate\Auth\Access\Response|bool
- */
- public function view(User $user, Article $article)
- {
- return $user->can('view-article');
- }
-
- /**
- * Determine whether the user can create models.
- *
- * @param User $user
- * @return \Illuminate\Auth\Access\Response|bool
- */
- public function create(User $user)
- {
- return $user->can('create-article');
- }
-
- /**
- * Determine whether the user can update the model.
- *
- * @param User $user
- * @param Article $article
- * @return \Illuminate\Auth\Access\Response|bool
- */
- public function update(User $user, Article $article)
- {
- return $user->can('update-article');
- }
-
- /**
- * Determine whether the user can delete the model.
- *
- * @param User $user
- * @param Article $article
- * @return \Illuminate\Auth\Access\Response|bool
- */
- public function delete(User $user, Article $article)
- {
- return $user->can('delete-article');
- }
-
- /**
- * Determine whether the user can restore the model.
- *
- * @param User $user
- * @param Article $article
- * @return \Illuminate\Auth\Access\Response|bool
- */
- public function restore(User $user, Article $article)
- {
- return $user->can('delete-article');
- }
-
- /**
- * Determine whether the user can permanently delete the model.
- *
- * @param User $user
- * @param Article $article
- * @return \Illuminate\Auth\Access\Response|bool
- */
- public function forceDelete(User $user, Article $article)
- {
- return $user->can('force-delete-article');
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Providers/ArticleServiceProvider.php b/tests/fixtures/stubs/valid/Article/Providers/ArticleServiceProvider.php
deleted file mode 100644
index 5da4a0d..0000000
--- a/tests/fixtures/stubs/valid/Article/Providers/ArticleServiceProvider.php
+++ /dev/null
@@ -1,116 +0,0 @@
-app->register(RouteServiceProvider::class);
- }
-
- /**
- * Bootstrap services.
- *
- * @return void
- */
- public function boot(): void
- {
- // $this->registerCommands();
- // $this->registerTranslations();
- // $this->registerViews();
- // $this->registerMigrations();
- }
-
- /**
- * Get the services provided by the provider.
- *
- * @return array
- */
- public function provides(): array
- {
- return [];
- }
-
- /**
- * Register artisan commands.
- *
- * @return void
- */
- public function registerCommands(): void
- {
- if ($this->app->runningInConsole()) {
- $this->loadCommands(module_path($this->moduleName, 'UI/CLI/Commands'));
- }
- }
-
- /**
- * Register translations.
- *
- * @return void
- */
- public function registerTranslations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/lang');
- $langPath = resource_path('lang/modules/' . $this->moduleNameLower);
-
- $this->loadTranslationsFrom($sourcePath, $this->moduleNameLower);
- }
-
- /**
- * Register views.
- *
- * @return void
- */
- public function registerViews(): void
- {
- $sourcePath = module_path($this->moduleName, 'Resources/views');
- $viewsPath = resource_path('views/modules/' . $this->moduleNameLower);
-
- $this->publishes([
- $sourcePath => $viewsPath
- ], 'views');
-
- $this->loadViewsFrom(
- array_merge($this->getPublishableViewPaths($this->moduleNameLower), [$sourcePath]),
- $this->moduleNameLower
- );
- }
-
- /**
- * Register migrations.
- *
- * @return void
- */
- public function registerMigrations(): void
- {
- $sourcePath = module_path($this->moduleName, 'Data/Migrations');
- $migrationsPath = database_path('migrations');
-
- $this->publishes([
- $sourcePath => $migrationsPath
- ], 'migrations');
-
- $this->loadMigrationsFrom($sourcePath);
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Providers/DeferredServiceProvider.php b/tests/fixtures/stubs/valid/Article/Providers/DeferredServiceProvider.php
deleted file mode 100644
index 653a61d..0000000
--- a/tests/fixtures/stubs/valid/Article/Providers/DeferredServiceProvider.php
+++ /dev/null
@@ -1,35 +0,0 @@
-bind('foo', function () {
- return 'bar';
- });
-
- app()->bind('deferred', function () {
- return;
- });
- }
-
- /**
- * Get the services provided by the provider.
- *
- * @return array
- */
- public function provides()
- {
- return ['deferred'];
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/Providers/RouteServiceProvider.php b/tests/fixtures/stubs/valid/Article/Providers/RouteServiceProvider.php
deleted file mode 100644
index 53f0711..0000000
--- a/tests/fixtures/stubs/valid/Article/Providers/RouteServiceProvider.php
+++ /dev/null
@@ -1,73 +0,0 @@
-mapApiRoutes();
- $this->mapWebRoutes();
- }
-
- /**
- * Define the "web" routes for the application.
- *
- * These routes all receive session state, CSRF protection, etc.
- *
- * @return void
- */
- protected function mapWebRoutes(): void
- {
- Route::middleware('web')
-// ->namespace('App\\Modules\\Article\\UI\\WEB\\Controllers')
- ->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/WEB/Routes'));
- });
- }
-
- /**
- * Define the "api" routes for the application.
- *
- * These routes are typically stateless.
- *
- * @return void
- */
- protected function mapApiRoutes(): void
- {
- Route::prefix('api')
- ->middleware('api')
-// ->namespace('App\\Modules\\Article\\UI\\API\\Controllers')
- ->group(function () {
- $this->loadRoutesFromDirectory(module_path($this->moduleName, 'UI/API/Routes'));
- });
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/QueryWizards/ArticleQueryWizard.php b/tests/fixtures/stubs/valid/Article/UI/API/QueryWizards/ArticleQueryWizard.php
deleted file mode 100644
index 746c94f..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/QueryWizards/ArticleQueryWizard.php
+++ /dev/null
@@ -1,48 +0,0 @@
-user()->can('create', Article::class);
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/Requests/DeleteArticleRequest.php b/tests/fixtures/stubs/valid/Article/UI/API/Requests/DeleteArticleRequest.php
deleted file mode 100644
index 6088a69..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/Requests/DeleteArticleRequest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-route('article');
- return $article && $this->user()->can('delete', $article);
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/Requests/ListArticlesRequest.php b/tests/fixtures/stubs/valid/Article/UI/API/Requests/ListArticlesRequest.php
deleted file mode 100644
index f5f36cd..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/Requests/ListArticlesRequest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-user()->can('viewAny', Article::class);
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/Requests/UpdateArticleRequest.php b/tests/fixtures/stubs/valid/Article/UI/API/Requests/UpdateArticleRequest.php
deleted file mode 100644
index 137cc3b..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/Requests/UpdateArticleRequest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-route('article');
- return $article && $this->user()->can('update', $article);
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/Requests/ViewArticleRequest.php b/tests/fixtures/stubs/valid/Article/UI/API/Requests/ViewArticleRequest.php
deleted file mode 100644
index 4903a09..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/Requests/ViewArticleRequest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-route('article');
- return $article && $this->user()->can('view', $article);
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/Resources/ArticleResource.php b/tests/fixtures/stubs/valid/Article/UI/API/Resources/ArticleResource.php
deleted file mode 100644
index 57aaa1c..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/Resources/ArticleResource.php
+++ /dev/null
@@ -1,19 +0,0 @@
-name('api.articles.create');
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/delete_article.php b/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/delete_article.php
deleted file mode 100644
index cceba8f..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/delete_article.php
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.delete');
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/list_articles.php b/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/list_articles.php
deleted file mode 100644
index 093f946..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/list_articles.php
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.list');
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/update_article.php b/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/update_article.php
deleted file mode 100644
index 7e76fc3..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/update_article.php
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.update');
diff --git a/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/view_article.php b/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/view_article.php
deleted file mode 100644
index 98fedcf..0000000
--- a/tests/fixtures/stubs/valid/Article/UI/API/Routes/v1/view_article.php
+++ /dev/null
@@ -1,7 +0,0 @@
-name('api.articles.view');
diff --git a/tests/fixtures/stubs/valid/Article/composer.json b/tests/fixtures/stubs/valid/Article/composer.json
deleted file mode 100644
index 035ed79..0000000
--- a/tests/fixtures/stubs/valid/Article/composer.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "laraneat/article",
- "description": "Article module",
- "authors": [
- {
- "name": "Salakhutdinov Salavat",
- "email": "salahutdinov.salavat@gmail.com"
- }
- ],
- "autoload": {
- "psr-4": {
- "App\\Modules\\Article\\": ""
- }
- },
- "require": {
- "php": "^8.0"
- },
- "require-dev": {
- "orchestra/testbench": "^6.2",
- "phpunit/phpunit": "^9.5"
- }
-}
diff --git a/tests/fixtures/stubs/valid/Article/module.json b/tests/fixtures/stubs/valid/Article/module.json
deleted file mode 100644
index d843c3a..0000000
--- a/tests/fixtures/stubs/valid/Article/module.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "Article",
- "namespace": "App\\Modules\\Article",
- "version": "0.1",
- "alias": "article",
- "description": "article module",
- "keywords": [],
- "priority": 0,
- "providers": [
- "App\\Modules\\Article\\Providers\\ArticleServiceProvider",
- "App\\Modules\\Article\\Providers\\DeferredServiceProvider"
- ],
- "aliases": {},
- "files": [],
- "requires": [
- "required_module"
- ]
-}
diff --git a/tests/fixtures/stubs/valid/Requirement/module.json b/tests/fixtures/stubs/valid/Requirement/module.json
deleted file mode 100644
index 62a1dec..0000000
--- a/tests/fixtures/stubs/valid/Requirement/module.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "Requirement",
- "alias": "required_module",
- "namespace": "App\\Modules\\Requirement",
- "description": "module that Article requires",
- "version": "0.1",
- "keywords": [],
- "order": 1,
- "providers": [
- ],
- "aliases": [],
- "files": [],
- "requires": []
-}
diff --git a/tests/fixtures/stubs/valid/module.json b/tests/fixtures/stubs/valid/module.json
deleted file mode 100644
index 16973d4..0000000
--- a/tests/fixtures/stubs/valid/module.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "name": "Order",
- "alias": "order",
- "namespace": "App\\Modules",
- "description": "My demo module",
- "version": "0.1",
- "keywords": [
- "my",
- "stub",
- "module"
- ],
- "active": 1,
- "order": 1,
- "providers": [
- "App\\Modules\\Order\\Providers\\OrderServiceProvider",
- "App\\Modules\\Order\\Providers\\EventServiceProvider",
- "App\\Modules\\Order\\Providers\\RouteServiceProvider"
- ],
- "aliases": [],
- "files": []
-}