> 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/application-behavior/11-side-effects.md).

# 11. Helpers, jobs, mail, notices

Side effects in LaraBoom do not need `Jobs/`, `Listeners/` or `Mail/` folders. Entity methods are marked with attributes. Calls go through short helpers from `LaraBoom\Author`.

## Helper table

| Helper                                           | Purpose                                        |
| ------------------------------------------------ | ---------------------------------------------- |
| `fire($event, ...$payload)`                      | a Laravel event (`event()`)                    |
| `go($job, ...$args)`                             | a sync or queued job on a method with `#[Job]` |
| `send($mail, $to, ...$args)`                     | a mail from a method with `#[Mail]`            |
| `notify($notifiable, $notice, ...$args)`         | a notice from a method with `#[Notice]`        |
| `remember($key, $ttl, $callback)`                | `Cache::remember`                              |
| `note($message, $context = [], $level = 'info')` | a log (the `boom` channel if configured)       |
| `store($file, $disk = 'public', $path = null)`   | save an UploadedFile                           |
| `check($data, $rules)`                           | validate and return an array                   |
| `boom($key, $default = null)`                    | a value from `App::share()`                    |

Import them like this:

```php
use function LaraBoom\Author\fire;
use function LaraBoom\Author\go;
use function LaraBoom\Author\note;
// ...
```

The package autoloads `helpers.php`.

## Events. fire and On

```php
// producer
fire('demo.created', $demo->id);

// listener on the Resource
#[On('demo.created')]
public function whenCreated(int $id): void
{
    note('demos.listener', ['id' => $id]);
}
```

`fire` with a string passes the payload into `event($name, $payload)`. With an event object it calls `event($object)`.

## Jobs. go and Job

```php
#[Job] // queue = true by default
public function touchCache(int $id): void
{
    note('demos.job', ['id' => $id]);
}

// the call
go([self::class, 'touchCache'], (int) $demo->id);
```

`#[Job(queue: false)]` runs synchronously inside `go` (the runner handles it without a dispatch). Otherwise it goes to the queue. In Docker the `queue` service runs `php boom queue:work`.

The target method can live on a Resource (as in Demo) or on a separate stub from `php boom make ... --type=job` (colocated under Resources).

## Mail. send and Mail

```php
#[Mail('Demo welcome')]
public function welcomeMail(Model $demo): string
{
    return "<p>Hello {$demo->name}, welcome to LaraBoom demo.</p>";
}

send([DemoResource::class, 'welcomeMail'], $demo->email, $demo);
```

The mail subject is the attribute argument. The body is the returned string (HTML in Demo). The runner wraps that into a Mailable.

Configure `MAIL_*` in `.env`. For local work it is often `log` or Mailpit.

## Notices. notify and Notice

```php
#[Notice(via: ['database'])]
public function pingNotice(object $notifiable, Model $demo): array
{
    return [
        'message' => "Demo #{$demo->id} ping",
        'demo_id' => $demo->id,
    ];
}

notify($user, [DemoResource::class, 'pingNotice'], $demo);
```

`via` is the Laravel Notification channels (`database`, `mail` and others). The notifiable must support the channels (AuthUser / User).

In the Demo Path `notifySelf` sends both a mail and a notice:

```php
send([DemoResource::class, 'welcomeMail'], $demo->email, $demo);
notify($user, [DemoResource::class, 'pingNotice'], $demo);
```

## Logs. note

```php
note('demos.created', ['id' => $demo->id, 'name' => $demo->name]);
note('path.ping', ['via' => 'path'], 'info');
```

If the logging config has a `boom` channel, it writes there. Otherwise the default. The request id is added automatically over HTTP.

## Cache. remember

```php
$stats = remember('demo.stats', 60, fn () => [
    'active' => app(Demo::class)->query()->where('status', 'active')->count(),
]);
```

## Share. boom

```php
$title = boom('demo_name', 'LaraBoom');
```

The keys are set in `App::share()`.

## The Demo pattern after create

```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);
}
```

One hook. A log, an event, a job. The `#[On]` listener and the job write their own `note`. The chain is visible in the logs by request id and entity id.

## When to move it into a separate file

An attribute on the Resource is enough while the method is short. When a real domain service appears, put `Product/Service.php` next to it. Do not resurrect `app/Services`. Stubs: `php boom make ... --type=service|job|event|mail|notice`.

Next up is [Console and schedule](/laraboom/application-behavior/12-console-schedule.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/application-behavior/11-side-effects.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.
