> 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/05-fields.md).

# 5. Fields and relations

Fields are declared with helpers from `LaraBoom\Author` inside `fields()`. Every `Field` knows its column type, validation rules, indexes and list flags.

## Quick helper reference

| Helper                          | Column / meaning           | Notes                                           |
| ------------------------------- | -------------------------- | ----------------------------------------------- |
| `Text($name, ...)`              | string                     | `needed`, `max`, `starts_as`, `unique`, `index` |
| `Story($name, ...)`             | text                       | long text                                       |
| `Email($name, ...)`             | string + email rules       | `needed` is true by default                     |
| `Secret($name='password')`      | hashed secret              | never lands in `present()`                      |
| `Number($name, ...)`            | integer                    | `min` / `max`                                   |
| `YesNo($name)`                  | boolean                    | `starts_as`                                     |
| `OneOf($name, $options)`        | enum string                | the list of allowed values                      |
| `OnDay($name)`                  | date                       |                                                 |
| `Money($name, currency: 'RUB')` | integer (kopecks or cents) | see present below                               |
| `Upload($name, disk: 'public')` | path string + file rules   |                                                 |
| `Link($name, to: Class)`        | `{name}_id` FK             |                                                 |

Relations (Eloquent, not columns):

| Helper                        | Purpose   |
| ----------------------------- | --------- |
| `BelongsTo($name, $to, $fk?)` | belongsTo |
| `HasMany($name, $to, $fk)`    | hasMany   |

## Fluent field API

```php
Text('name', needed: true, max: 255)->sort()->filter()
Money('price', currency: 'RUB')->sort()->filter()
Link('parent', to: self::class)->filter()
Text('slug')->unique()->was('old_slug')
```

The important chains:

* `->filter()` makes the field a list query filter (`?status=active`)
* `->sort()` allows the field in `?sort=`
* `->was('old_column')` sets a rename during sync
* `->unique()` and `->index()` put schema indexes in place
* `->readonly()` does not accept a value from input where this is supported
* `->rules([...])` adds Laravel validator rules
* `->default($value)` sets the default value

## A full set example (Demo)

```php
public function fields(): array
{
    return [
        Text('name', needed: true, max: 255)->sort()->filter(),
        Email('email', unique: true),
        Secret('password'),
        Story('bio'),
        Money('price', currency: 'RUB')->sort()->filter(),
        Number('stock', needed: true, min: 0, starts_as: 0)->sort(),
        OneOf('status', ['draft', 'active', 'archived'], starts_as: 'draft')->filter()->sort(),
        YesNo('featured', starts_as: false)->filter(),
        OnDay('starts_on', needed: false),
        Upload('cover'),
        Link('parent', to: self::class)->filter(),
    ];
}
```

## Money

The database stores an integer in the smallest currency units. Validation is `integer` and `min:0`.

In `present()`:

* `price` is kopecks
* `price_amount` is a string like `99.00`
* `price_currency` is the currency code (`RUB`)

It is convenient for an API client to display `*_amount` and to write back integers.

## Upload

The rules are `file` or `nullable|file`. On the disk it is a path. In `present()`:

* `cover` is the path
* `cover_url` is the public disk URL where applicable

Manual saving is done by the `store($uploadedFile, $disk, $path)` helper.

## Link and FK

```php
Link('parent', to: self::class)
```

The column becomes `parent_id` if the name does not end with `_id`. Sync creates and maintains the foreign key to the table of the target Resource.

The optional `show` argument affects how the relation is shown in the metadata and OpenAPI. Look at the helper signature.

## Relations()

```php
public function relations(): array
{
    return [
        BelongsTo('parent', self::class, 'parent_id'),
        HasMany('children', self::class, 'parent_id'),
    ];
}
```

`#[With('parent')]` on the class loads `parent` in `query()`. Nested JSON appears only for relations that are already loaded.

## Present

`Resource::present($model)` builds the API response:

1. skips secret fields
2. expands money and upload
3. adds timestamps if they are enabled in `#[Migrate]`
4. nests loaded relations through their Resource::present

Do not put heavy business logic in present. For a custom shape a separate `#[Get('...')]` action is better.

## Seeds through Sample

The order of values in `Sample(...)` matches the order of fields in `fields()`:

```php
public function seeds(): Examples
{
    return Examples(
        Sample('Ada Lovelace', 'ada@demo.boom', 'password', 'First seed row.', 4500, 12, 'active', true),
        Sample('Grace Hopper', 'grace@demo.boom', 'password', 'Second seed row.', 12900, 8, 'active', false),
    );
}
```

More on that in [chapter 13](/laraboom/application-behavior/13-seeding-make.md).

## Renames and evolution

Changed a column name in code? Keep the old one through `->was('old_name')`, then run `php boom sync`. Without `was` sync sees a removed column and a new one. `sync:prune` removes extra columns from the database deliberately and only with `--force`.

Next up is [Schema and sync](/laraboom/data-model/06-schema.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/05-fields.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.
