> For the complete documentation index, see [llms.txt](https://vladimirkostikov.gitbook.io/laraboom/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://vladimirkostikov.gitbook.io/laraboom/data-model/04-resources.md).

# 4. Resources

A Resource is the central entity of LaraBoom. It describes the table, field validation, CRUD permissions, relations, seeds, model hooks and custom API actions.

## Base contract

The class lives in `app/Resources`, extends `LaraBoom\Definition\Resource` and implements at least `fields()`.

```php
namespace App\Resources;

use LaraBoom\Attributes\Migrate;
use LaraBoom\Definition\Resource;
use function LaraBoom\Author\Text;

#[Migrate]
final class Post extends Resource
{
    public function fields(): array
    {
        return [
            Text('title', needed: true, max: 255),
            Text('body'),
        ];
    }
}
```

The resource name in URLs and Gates is the plural snake form of the class basename. The class `Post` gives `posts`. The table is the same by default.

The model is created dynamically (`ResourceModel`) until you override `model()` or add `#[Account]`. Then it becomes `AuthUser`.

## Class attributes

### Migrate

Includes the resource in the declarative schema sync.

```php
#[Migrate(timestamps: true, softDeletes: false)]
#[Migrate(softDeletes: true)]
```

* with `timestamps: true` (the default) you get `created_at` and `updated_at`
* with `softDeletes: true` you get `deleted_at` and soft deletion in `query()` / `delete()`

Without `#[Migrate]` a Resource can exist in code, but `sync` and `rebuild` do not manage its table as a migrate resource.

### Account

Marks the Resource as the auth provider user.

* the model becomes `AuthUser`
* sync adds `email_verified_at` and `remember_token`
* `auth.providers.users.model` is bound to this model

Demo does exactly this:

```php
#[Account]
#[Migrate(softDeletes: true)]
final class Demo extends Resource { ... }
```

### With

Default eager load for `query()`. The attribute is repeatable.

```php
#[With('parent')]
```

In `present()` the already loaded relations are nested into the JSON through the `present()` of the related Resource.

### Allow

Permissions for CRUD and arbitrary actions. In detail in [chapter 9](/laraboom/http/09-authorization.md).

```php
#[Allow('index', true)]
#[Allow('show', true)]
#[Allow('store', true)]
#[Allow('update', 'auth')]
#[Allow('destroy', 'auth')]
```

`true` allows everyone. `auth` allows authenticated users only. There are also `guest`, `owner` and the name of a method on the Resource. See Access.

### Seed

If `seeds()` is empty, the autofiller can create N rows through `#[Seed(count: 2)]`. In Demo the seeds are set explicitly through `seeds()`.

## Resource methods

| Method               | Purpose                                               |
| -------------------- | ----------------------------------------------------- |
| `fields(): array`    | the list of `Field`                                   |
| `relations(): array` | `BelongsTo` / `HasMany`                               |
| `seeds(): Examples`  | demo data                                             |
| `query()`            | the base Eloquent builder (scopes, with, soft delete) |
| `present(Model)`     | the JSON representation of a row                      |
| `table()` / `name()` | table and resource names                              |

On top of that you attach methods with lifecycle, Filter, Scope, HTTP, Job, Mail and Notice attributes.

## Scope and Filter

### Scope

Always applied in `query()`.

```php
#[Scope]
public function hideArchived(Builder $query): void
{
    $query->where($this->table().'.status', '!=', 'archived');
}
```

### Filter

A query parameter of the list. The key is the attribute argument or the method name.

```php
#[Filter('min_price')]
public function minPrice(Builder $query, mixed $value): void
{
    $query->where('price', '>=', (int) $value);
}
```

The request looks like this. `GET /api/demos?min_price=1000`.

Field filters are enabled through `->filter()` on the Field. See [fields](/laraboom/data-model/05-fields.md).

## Model lifecycle hooks

Attributes on Resource methods:

* `#[Creating]` `#[Created]`
* `#[Updating]` `#[Updated]`
* `#[Saving]` `#[Saved]`
* `#[Deleting]` `#[Deleted]`

A Demo example:

```php
#[Created]
public function afterCreate(Model $demo): void
{
    note('demos.created', ['id' => $demo->id, 'name' => $demo->name]);
    fire('demo.created', $demo->id);
    go([self::class, 'touchCache'], (int) $demo->id);
}
```

`#[Atomic]` on a method wraps the call into a DB transaction where the runtime supports it.

## Events, jobs, mail, notices on a Resource

```php
#[On('demo.created')]
public function whenCreated(int $id): void { ... }

#[Job]
public function touchCache(int $id): void { ... }

#[Mail('Demo welcome')]
public function welcomeMail(Model $demo): string { ... }

#[Notice(via: ['database'])]
public function pingNotice(object $notifiable, Model $demo): array { ... }
```

From the outside they are called through the `fire`, `go`, `send` and `notify` helpers. See [chapter 11](/laraboom/application-behavior/11-side-effects.md).

## Custom HTTP actions on a Resource

```php
#[Get('ping')]
public function ping(): array
{
    return ['ok' => true, 'resource' => $this->name()];
}

#[Post('echo', only: 'api')]
#[Throttle(60, 1)]
public function echoPayload(Request $request): array
{
    return ['echo' => $request->all()];
}
```

Registration happens under `/api/{resourceName}/{uri}`. Examples are `GET /api/demos/ping` and `POST /api/demos/echo`.

`only: 'api'` puts the route into the API middleware stack.

## Default CRUD operations

The runtime (`CrudHandler`) serves:

* `index` with pagination of 15 and `present`
* `show`
* `store` with status 201
* `update`
* `destroy` with status 204 (soft delete if enabled)

Every operation goes through the `{resource}.{action}` Gate from `#[Allow]`.

## The full reference

Read `apps/app/Resources/Demo.php` in full. It is the official feature tour. Account, soft deletes, the main fields, relations, scope and filter, seeds, Created, On, Job, Mail, Notice, ping and echo.

Next up is [Fields and relations](/laraboom/data-model/05-fields.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://vladimirkostikov.gitbook.io/laraboom/data-model/04-resources.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
