---
title: "Opt-in traits — Package Toolkit for Laravel | Roundly"
description: "Idempotent gate, Blade directive and schema-macro registration — a double boot never clobbers or double-registers anything."
url: https://roundly-consulting.com/open-source/docs/package-toolkit-for-laravel/opt-in-traits
language: en
---

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

[Package Toolkit for Laravel](https://roundly-consulting.com/open-source/docs/package-toolkit-for-laravel.md)

# Opt-in traits

Three traits add registration helpers to your provider. Each centralizes an idempotency guard, so a double boot — package discovery plus an explicit provider registration, for example — never clobbers or double-registers anything:

```php
use RoundlyConsulting\PackageToolkit\Concerns\InteractsWithGates;
use RoundlyConsulting\PackageToolkit\Concerns\RegistersBladeDirectives;
use RoundlyConsulting\PackageToolkit\Concerns\RegistersBlueprintMacros;

final class CommentsServiceProvider extends PackageServiceProvider
{
    use InteractsWithGates;
    use RegistersBladeDirectives;
    use RegistersBlueprintMacros;

    public function boot(): void
    {
        parent::boot();

        $this->registerBlueprintMacros();                      // ownerKey/morphKey/auditable/polymorphicSubject/whereLikeEscaped
        $this->registerBladeDirective('comment', $handler);    // no-op if already registered
        $this->registerBladeIf('commented', $condition);       // @commented(...) … @else … @endcommented
        $this->defineGate('manage-comments', $callback);       // left untouched if the host defined it
    }
}
```

## InteractsWithGates

defineGate(string $ability, callable|string $callback) defines an authorization gate only when the host has not defined that ability already — a package never overrides the host’s own policy for the same ability.

## RegistersBladeDirectives

registerBladeDirective(string $name, callable $handler) registers a Blade directive. registerBladeIf(string $name, callable $condition) registers a conditional one from a callback returning a boolean, which Blade expands into @name, @elsename, @unlessname and @endname. A name already taken in any of those four forms is left untouched:

```php
// boot()
$this->registerBladeIf('commentsEnabled', static fn (bool $flag): bool => $flag);
```

```blade
@commentsEnabled($flag)
    Comments are open.
@else
    Comments are closed.
@endcommentsEnabled

@unlesscommentsEnabled($flag)
    Comments are closed.
@endcommentsEnabled
```

## RegistersBlueprintMacros

registerBlueprintMacros() registers the ownerKey(), morphKey(), auditable() and polymorphicSubject() schema macros on Blueprint, and the whereLikeEscaped() macro on both the query and the Eloquent builder. Each one is guarded by the framework’s own macro check. For usage, see Key types & schema macros and Database helpers.

One more trait, RedactsSensitiveArguments, goes on your package’s facade rather than its provider — see Secrets in config and facades.

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