---
title: "Declarative conditions — Onboarding for Laravel | Roundly"
description: "completeWhenFilled(), completeWhenTrue(), completeWhenHas() and their exclude counterparts — one-line rules, no closures."
url: https://roundly-consulting.com/open-source/docs/onboarding-for-laravel/declarative-conditions
language: en
---

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

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

# Declarative conditions

For the common cases you don’t need a closure. These helpers read a value off the bound subject and compile down to the same completeIf / excludeIf rules, so they tolerate a null subject and stay fully stateless:

```php
Step::make('Upload photo')->completeWhenFilled('avatar_path');     // filled() on the attribute (dot paths supported)
Step::make('Verify email')->completeWhenTrue('email_verified_at'); // truthy attribute, or a public no-arg method
Step::make('Invite team')->completeWhenHas('teams');               // a non-empty relation value, collection, or array
```

| Method | Purpose |
| --- | --- |
| `completeWhenFilled($attribute)` | filled() on the attribute; dot paths supported. |
| `completeWhenTrue($attributeOrMethod)` | A public no-argument method’s result (never an Attribute accessor), or else the attribute, is truthy. |
| `completeWhenHas($relation)` | The relation value is a model, a non-empty collection or array, or any non-null value. |
| `excludeWhenFilled($attribute)` | The completeWhenFilled() check, used for exclusion. |
| `excludeWhenTrue($attributeOrMethod)` | The completeWhenTrue() check, used for exclusion. |
| `excludeWhenHas($relation)` | The completeWhenHas() check, used for exclusion. |

With a null subject every helper evaluates to false — the step is not complete and not excluded.

## Methods before attributes

completeWhenTrue() prefers a public no-argument method of that name over an attribute. A method that requires arguments is treated as no value rather than being called. A protected method — and, on an Eloquent model, an Attribute accessor such as protected function verified(): Attribute, public or protected — is never called: the attribute is read instead ($subject->verified), so the accessor’s value counts, not the Attribute object:

```php
// A public no-arg method wins over an attribute of the same name
Step::make('Subscribe')->completeWhenTrue('hasSubscription');   // calls $subject->hasSubscription()
```

## Relations never query

completeWhenHas() inspects the already-loaded or lazy-loaded relation value — it does not run ->exists() for you, which would assume Eloquent. When you need an explicit query, back completeWhenTrue() with a model method, or use a closure:

```php
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Onboarding\Traits\GetsOnboarded;

class User extends Model
{
    use GetsOnboarded;

    public function hasTeam(): bool
    {
        return $this->teams()->exists();
    }
}

// completeWhenHas() never queries — back an explicit query with a method
Step::make('Invite team')->completeWhenTrue('hasTeam');
```

## Exclusion

The same set exists on the exclude side. An excluded step disappears from steps(), from the percentages and from completion for that subject — each person only sees what applies to them:

```php
Step::make('Connect billing')->excludeWhenTrue('is_free_plan');     // hidden for free-plan users
Step::make('Upload photo')->excludeWhenFilled('social_avatar_url'); // already has an avatar elsewhere
Step::make('Create workspace')->excludeWhenHas('workspaces');       // joined an existing workspace
```

completeWhen() and excludeWhen() are aliases of completeIf() and excludeIf() for a consistent naming style:

```php
Step::make('Verify email')->completeWhen(fn (?User $user) => $user?->hasVerifiedEmail());
Step::make('Connect billing')->excludeWhen(fn (?User $user) => $user?->is_guest);
```

## 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/onboarding-for-laravel.md)
