# ArtisanGen

**Generate Laravel code from your database tables.**  
Create the tables first, then scaffold models, CRUD controllers, form requests, and views automatically.

ArtisanGen is inspired by Yii2 Gii and helps you build admin CRUD modules for this CMS.

- Controller: `app/Http/Controllers/Backend/ArtisanGenController.php`
- Views: `resources/views/backend/module/artisanGen/`
- Stubs: `stubs/`
- URL: `/admin/artisan-gen` (e.g. `http://127.0.0.1:8000/admin/artisan-gen`)
- Sidebar: **Backend** → **Module Generator** (located after **Theme**)

---

## Table of Contents

1. [Workflow Overview](#workflow-overview)
2. [Migration Generator](#migration-generator)
3. [Model Generator](#model-generator)
4. [CRUD Generator](#crud-generator)
5. [Generated File Locations](#generated-file-locations)
6. [Customizing Stubs](#customizing-stubs)
7. [Troubleshooting](#troubleshooting)

---

## Workflow Overview

There are two ways to start:

### Option A — Migration-first
1. Create and run a **Migration**.
2. Generate a **Model** from the new table.
3. Generate **CRUD** files from the model.
4. Add the suggested route to `routes/web.php`.

### Option B — DB-first
1. Create the table directly in the database (phpMyAdmin, TablePlus, etc.).
2. Generate a **Model** from the existing table.
3. Generate **CRUD** files from the model.
4. Add the suggested route to `routes/web.php`.

---

## Migration Generator

URL: `/admin/artisan-gen/migration`

Generate a Laravel migration file by typing fields.

### Table name rules
- Use **lowercase**, **plural**, **snake_case**.
- Examples: `products`, `order_items`, `backend_products`, `content_articles`.
- The generator auto-normalizes spaces, dashes, and CamelCase to snake_case.
  - `BackendProducts` → `backend_products`
  - `backend products` → `backend_products`
  - `backend-products` → `backend_products`

### Field format

```text
name:type(params):modifier:modifier(value)
```

Separate multiple fields with commas.

### Common column types

`string`, `text`, `longText`, `integer`, `bigInteger`, `smallInteger`, `tinyInteger`, `boolean`, `decimal(8, 2)`, `float(8, 2)`, `double(8, 2)`, `char(36)`, `date`, `dateTime`, `timestamp`, `json`, `jsonb`, `enum(['draft','published'])`, `set(['a','b'])`, `binary`, `uuid`, `foreignId`.

### Column modifiers

`nullable`, `unsigned`, `unique`, `index`, `primary`, `default(value)`, `comment('text')`, `first`, `after('column')`, `useCurrent`, `charset('utf8mb4')`, `collation('utf8mb4_unicode_ci')`, `constrained('users')`, `cascadeOnDelete`, `nullOnDelete`.

### Examples

```text
name:string, slug:string:unique, price:decimal(8, 2):nullable, stock:integer:unsigned:default(0), category_id:foreignId:constrained('categories'):cascadeOnDelete, is_active:boolean:default(true), published_at:datetime:nullable
```

### Primary Key
- Default: `id` → generates `$table->id();`.
- Custom name: enter `post_id` → generates `$table->id('post_id');`.
- Custom type: add a field with the same name as the Primary Key, e.g. Primary Key `uuid` + field `uuid:uuid:primary`.

### Run Migration
After generating, click **Run Migration** to execute `php artisan migrate` for the generated file.

---

## Model Generator

URL: `/admin/artisan-gen/model`

Generate a Laravel Eloquent model from an existing database table.

### Inputs

| Field | Description |
|---|---|
| Table Name | Select an existing table. Uses Select2 for search. |
| Model Name | Auto-filled from the table name. You can change it. |
| Namespace | Default: `app\Models\Backend`. Parent folder only — do not include the model name. Uses PHP namespace separator `\`; auto-converts to proper casing (`App\Models\Backend`). |
| Style | `PHP Attributes` (default) or `Class Properties`. |

### Namespace examples

> The namespace is the **parent folder** of the model file. The model name is appended automatically.

| Input | Generated PHP namespace | File path (for model `User`) |
|---|---|---|
| `app\Models\Backend` | `App\Models\Backend` | `app/Models/Backend/User.php` |
| `app\Models` | `App\Models` | `app/Models/User.php` |
| `app\Models\Backend\Catalog` | `App\Models\Backend\Catalog` | `app/Models/Backend/Catalog/User.php` |

### Generated model features
- `#[Table]` attribute (or `$table` property).
- `#[Fillable]` / `$fillable` from table columns.
- `casts()` with integer, boolean, datetime, date, json.
- `#[Hidden]` / `$hidden` for sensitive fields (`password`, `secret`, `pin`, etc.).
- Includes `created_by`, `updated_by`, and timestamp casts when present.

---

## CRUD Generator

URL: `/admin/artisan-gen/crud`

Generate a full admin CRUD from an existing model.

### Inputs

| Field | Description |
|---|---|
| Model Class | Select an existing model. Uses Select2 for search. |
| Controller Namespace | Default: `app\Http\Controllers\Backend` |
| Request Namespace | Default: `app\Http\Requests\Backend` |
| View Path | Default: `backend.module._gen.{camelCaseModel}`. Uses dot notation. |

### Generated files

| File | Default location |
|---|---|
| Controller | `app/Http/Controllers/Backend/{Model}Controller.php` |
| Form Request | `app/Http/Requests/Backend/{Model}Request.php` |
| Index View | `resources/views/backend/module/_gen/{camelCaseModel}/index.blade.php` |
| Create View | `resources/views/backend/module/_gen/{camelCaseModel}/create.blade.php` |
| Edit View | `resources/views/backend/module/_gen/{camelCaseModel}/edit.blade.php` |
| Setup Guide | `resources/views/backend/module/_gen/{camelCaseModel}/CRUD-SETUP.md` — route, permission, role, menu guide |

### View Path examples

| View Path | Folder |
|---|---|
| `backend.module._gen.products` | `resources/views/backend/module/_gen/products/` |
| `backend.module._gen.inventory.products` | `resources/views/backend/module/_gen/inventory/products/` |
| `admin.catalog.products` | `resources/views/admin/catalog/products/` |

### Generated controller features
- Index with search across all fields.
- Create, store, edit, update, destroy.
- Uses generated Form Request for validation.
- Uses `flash()` for success messages.

### After generating CRUD

A `CRUD-SETUP.md` file is generated in the same view folder with full instructions.

The route pattern used in this project is `Route::controller()` with explicit permission per route:

```php
use App\Http\Controllers\Backend\ContentProductController;

Route::controller(ContentProductController::class)->group(function () {
    Route::get('/content-products', 'index')->middleware('permission:content-products.view,admin')->name('content-products.index');
    Route::get('/content-products/create', 'create')->middleware('permission:content-products.create,admin')->name('content-products.create');
    Route::post('/content-products', 'store')->middleware('permission:content-products.create,admin')->name('content-products.store');
    Route::get('/content-products/{id}/edit', 'edit')->middleware('permission:content-products.update,admin')->name('content-products.edit');
    Route::put('/content-products/{id}', 'update')->middleware('permission:content-products.update,admin')->name('content-products.update');
    Route::delete('/content-products/{id}', 'destroy')->middleware('permission:content-products.delete,admin')->name('content-products.destroy');
});
```

Alternatively, use `Route::resource` for brevity:

```php
Route::resource('content-products', ContentProductController::class)
    ->middleware('permission:content-products.view|content-products.create|content-products.update|content-products.delete,admin');
```

Permissions needed: `{route}.view`, `.create`, `.update`, `.delete` — create them via seeder or `/admin/permission`, then assign to a role.

Add a sidebar menu item in `database/seeders/BackendMenuSeeder.php` if needed.

> ArtisanGen generates the files but does **not** auto-add routes, permissions, or menus — similar to Yii2 Gii.

---

## Generated File Locations

| Generator | Output |
|---|---|
| Migration | `database/migrations/YYYY_MM_DD_HHMMSS_create_{table}_table.php` |
| Model | Based on Namespace input, e.g. `app/Models/Backend/{Model}.php` |
| CRUD Controller | Based on Controller Namespace input |
| CRUD Request | Based on Request Namespace input |
| CRUD Views | Based on View Path input |

---

## Customizing Stubs

All templates are in `stubs/`:

| Stub | Used by |
|---|---|
| `stubs/migration.stub` | Migration Generator |
| `stubs/model-attributes.stub` | Model Generator (PHP Attributes style) |
| `stubs/model-properties.stub` | Model Generator (Class Properties style) |
| `stubs/controller.stub` | CRUD Generator — Controller |
| `stubs/request.stub` | CRUD Generator — Form Request |
| `stubs/views/index.stub` | CRUD Generator — Index view |
| `stubs/views/create.stub` | CRUD Generator — Create view |
| `stubs/views/edit.stub` | CRUD Generator — Edit view |
| `stubs/views/setup.stub` | CRUD Generator — CRUD-SETUP.md guide |

Edit these files to change the generated output across the whole project.

### Available placeholders

- `{{tableName}}`, `{{idLine}}`, `{{fields}}` — migration
- `{{namespace}}`, `{{modelName}}`, `{{tableName}}`, `{{primaryKey}}`, `{{fillable}}`, `{{casts}}`, `{{hiddenAttr}}`, `{{hiddenProp}}` — model
- `{{controllerNamespace}}`, `{{modelName}}`, `{{modelClass}}`, `{{requestClass}}`, `{{tableName}}`, `{{routePrefix}}`, `{{viewPath}}`, `{{primaryKey}}`, `{{searchClauses}}`, `{{storeFields}}` — controller
- `{{requestNamespace}}`, `{{modelName}}`, `{{rules}}` — request
- `{{modelName}}`, `{{routePrefix}}`, `{{headers}}`, `{{rows}}`, `{{colspan}}`, `{{formFields}}`, `{{formEditFields}}` — views

---

## Troubleshooting

### "Model class is required"
The frontend sends `modelClass` (camelCase) and the controller reads both `modelClass` and `model_class`. Make sure you select a model from the dropdown.

### "Table name is required"
Enter a table name. Spaces and dashes are auto-converted to underscores.

### Generated route not working
Remember that CRUD Generator does **not** add routes automatically. Copy the suggested route into `routes/web.php` inside the admin route group.

### Views not found after CRUD generation
Check that the View Path matches the actual folder under `resources/views/`. The default uses camelCase to match this project's convention.

---

## Menu / Sidebar

The sidebar menu item is managed through the backend menu system.

- For fresh installs: the menu is created by `database/seeders/BackendMenuSeeder.php`.
- For existing databases: re-run the seeder to add the menu:
  ```bash
  php artisan db:seed --class=BackendMenuSeeder
  php artisan cache:clear
  ```

## Permissions

All ArtisanGen routes are protected by the `artisangen.view` permission (admin guard).

- The permission is created automatically by `BackendMenuSeeder`.
- By default it is assigned to the `super-admin` role.
- Users without this permission will get a 403 error when accessing `/admin/artisan-gen` or any of its sub-pages.

## Related Files

- `app/Http/Controllers/Backend/ArtisanGenController.php`
- `routes/web.php` (admin `artisan-gen` routes)
- `resources/views/backend/module/artisanGen/`
- `stubs/`
- `database/seeders/BackendMenuSeeder.php`
