# Category integration guide

This application uses a **single `categories` table** with optional type scoping via the `type` column (model class FQCN). Categories are **type-level** only (a category belongs to exactly one model type via `categories.type`), and per-record assignment is done through the **global polymorphic pivot** table `categorizables`.

## Enable categories on a model

1. Add the `HasCategory` trait to your Eloquent model.
2. Define a type label via `protected string $categoryModule` or `getCategoryModule()`.

```php
<?php

namespace App\Models;

use App\Traits\HasCategory;
use Illuminate\Database\Eloquent\Model;

class Blog extends Model
{
    use HasCategory;

    protected string $categoryModule = 'Blog';
}
```

When the model boots, it registers with `CategoryRegistry` and appears in the admin **Type** dropdown automatically.

## Database scoping

| Scenario | `type` column |
|----------|---------------|
| Uncategorized | `null` |
| Type-level (e.g. all Blog categories) | `App\Models\Blog::class` |

Admin CRUD always sets only `type` (via the `type` request field / registry key).

## Slugs

Slugs are unique **within the same `type` and `parent_id`**, not globally. For example, a parent category named `test` under uncategorized (`type = null`) gets slug `test`, and another parent category named `test` under `App\Models\Blog` also gets slug `test`. A numeric suffix (`test-1`, `test-2`, …) is only added when the same slug already exists for that type and parent.

## Relations

**On `Category`:**

```php
$category->parent();   // belongsTo Category
$category->children(); // hasMany Category
```

**On your model (via `HasCategory`):**

```php
Blog::typeCategoriesQuery()->get(); // categories where type = Blog::class
```

**Per-record assignment (many categories per record):**

```php
$blog->categories(); // morphToMany Category via `categorizables`
$blog->syncCategories([$catId1, $catId2]);
```

Implement `countUsingCategory()` on the model when you need delete warnings:

```php
public static function countUsingCategory(int $categoryId): int
{
    // default implementation counts in `categorizables` for this model type
    return parent::countUsingCategory($categoryId);
}
```

## Registry API

```php
use App\Support\Category\CategoryRegistry;

$registry = app(CategoryRegistry::class);
$registry->options();           // key => label for selects
$registry->resolveType($key);   // model class or null
```

## Admin UI

- Route: `admin.categories.index`
- AJAX listing, modal create/edit, confirm delete
- Parent dropdown: `GET /admin/categories/parents?type={key}`

## Image storage

Files use the `categoryImages` disk: `public/uploads/categories/`.

## Do not create

- Duplicate category tables per type
- Per-category morph ids on `categories` (keep `categories.type` as the type scope)
