---
title: "Fluent builder — Addresses for Laravel | Roundly"
description: "Create addresses with Addresses::for()->new() or newAddress() — a readable PendingAddress chain that refuses incomplete addresses."
url: https://roundly-consulting.com/open-source/docs/addresses-for-laravel/fluent-builder
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Addresses for Laravel](https://roundly-consulting.com/open-source/docs/addresses-for-laravel.md)

# Fluent builder

Addresses::for($model)->new() and $model->newAddress() both return a PendingAddress. Chain the fields, then save() persists the address and returns it. Country codes are normalised automatically, and an address with no type() gets the configured default\_type:

```php
use RoundlyConsulting\Addresses\Enums\AddressType;
use RoundlyConsulting\Addresses\Facades\Addresses;

Addresses::for($payer)->new()
    ->type(AddressType::Office)
    ->name('HQ')
    ->primary()
    ->in('Bratislava')->at('Somewhere 1')->postalCode('81101')->country('sk')
    ->meta(['floor' => 3])
    ->save();

// or from the model
$payer->newAddress()
    ->type(AddressType::Home)
    ->in('Košice')->at('Main 2')->postalCode('04001')->country('SK')
    ->save();
```

## Builder methods

| Method | Effect |
| --- | --- |
| `type(AddressType $type)` | Address type — without it, the configured default\_type. |
| `name(string $name)` | Optional label, e.g. HQ; a blank name is stored as null. |
| `in(string $city)` | City — required. |
| `at(string $street)` | Street line — required. |
| `postalCode(string $postalCode)` | Postal code — required. |
| `country(string $country)` | ISO country code — required; normalised on save. |
| `primary(bool $isPrimary = true)` | Make it the primary address of its type; siblings are demoted on save, in the same transaction. |
| `meta(iterable $meta)` | Arbitrary extras, wrapped in a Collection and stored as JSON. |
| `save(): Address` | Checks the four required fields, adds the address through the owner’s address book and returns it. |

## Required fields

City, street, postal code and country are required. Calling save() without all four — or with a blank value — throws IncompleteAddressException naming every missing field:

```php
use RoundlyConsulting\Addresses\Exceptions\IncompleteAddressException;

try {
    $customer->newAddress()->in('Bratislava')->save();
} catch (IncompleteAddressException $e) {
    $e->getMessage();
    // 'The address is missing required field(s): [street, postalCode, country].'
}
```

## What save() does

The collected fields pass through AddressData::make() — strings are trimmed, a blank name becomes null, the country is normalised and a missing type becomes default\_type — and save() adds the result through the owner’s address book, so Addresses::fake() sees it too. CreateAddressAction inserts the row on the owner’s morph relation and, when primary() was set, promotes it in the same transaction, demoting the other addresses of that type. Then AddressCreated is dispatched, followed by PrimaryAddressChanged for a promotion.

Addresses::for() accepts any Eloquent model — the HasAddresses trait is only needed for the model-side helpers.

## From a request

```php
use App\Models\Customer;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use RoundlyConsulting\Addresses\Enums\AddressType;
use RoundlyConsulting\Addresses\Http\Resources\AddressResource;

final class CustomerAddressController
{
    public function store(Request $request, Customer $customer): AddressResource
    {
        $data = $request->validate([
            'type' => ['required', Rule::enum(AddressType::class)],
            'city' => ['required', 'string', 'max:255'],
            'street' => ['required', 'string', 'max:255'],
            'postal_code' => ['required', 'string', 'max:255'],
            'country' => ['required', 'string', 'min:2', 'max:3'],
            'primary' => ['boolean'],
        ]);

        $address = $customer->newAddress()
            ->type(AddressType::from($data['type']))
            ->in($data['city'])
            ->at($data['street'])
            ->postalCode($data['postal_code'])
            ->country($data['country'])            // 'sk' is stored as 'SK'
            ->primary($request->boolean('primary'))
            ->save();

        return AddressResource::make($address);
    }
}
```

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/addresses-for-laravel.md)
