PHPackages                             ivanfuhr/essentials - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. ivanfuhr/essentials

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

ivanfuhr/essentials
===================

Just better defaults for your Laravel projects.

v1.0.2(1mo ago)04[2 PRs](https://github.com/ivanfuhr/essentials/pulls)MITPHPPHP ^8.3.0CI passing

Since Jun 1Pushed 1mo agoCompare

[ Source](https://github.com/ivanfuhr/essentials)[ Packagist](https://packagist.org/packages/ivanfuhr/essentials)[ GitHub Sponsors](https://github.com/ivanfuhr)[ RSS](/packages/ivanfuhr-essentials/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (3)Dependencies (20)Versions (7)Used By (0)

Essentials
==========

[](#essentials)

 [![Build Status](https://github.com/ivanfuhr/essentials/actions/workflows/tests.yml/badge.svg)](https://github.com/ivanfuhr/essentials/actions) [![Total Downloads](https://camo.githubusercontent.com/8f0cb52b5b63fdb4cefc4a8e51849704fd375f70e19198f17e4a3915d6f741e3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6976616e667568722f657373656e7469616c73)](https://packagist.org/packages/ivanfuhr/essentials) [![Latest Stable Version](https://camo.githubusercontent.com/b8b89f961a9c255da16d61ca7f7a3f65766d80370b44ed8c4568788698ea42f8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6976616e667568722f657373656e7469616c73)](https://packagist.org/packages/ivanfuhr/essentials) [![License](https://camo.githubusercontent.com/2ff7018ae1dbdef35a3fe1a1ff8fc340257bb24aaf1776334e511507a2f44853/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6976616e667568722f657373656e7469616c73)](https://packagist.org/packages/ivanfuhr/essentials)

Essentials provide **better defaults** for your Laravel applications including strict models, automatically eagerly loaded relationships, immutable dates, a lightweight `Result` type for service outcomes, and more!

> **Requires [PHP 8.3+](https://php.net/releases/)**, **[Laravel 11+](https://laravel.com/docs/11.x/)**.

> **Note:** This package modifies the default behavior of Laravel. **It is recommended to use it in new projects** or when you are comfortable with the changes it introduces.

Installation
------------

[](#installation)

⚡️ Get started by requiring the package using [Composer](https://getcomposer.org):

```
composer require ivanfuhr/essentials
```

Features
--------

[](#features)

All features are optional and configurable in `config/essentials.php`.

You may publish the configuration file with:

```
php artisan vendor:publish --tag=essentials-config
```

Table of Contents
-----------------

[](#table-of-contents)

- [Strict Models](#-strict-models)
- [Auto Eager Loading](#-auto-eager-loading)
- [Optional Unguarded Models](#-optional-unguarded-models)
- [Immutable Dates](#-immutable-dates)
- [Force HTTPS](#-force-https)
- [Safe Console](#-safe-console)
- [Prevent Stray Requests](#-prevent-stray-requests)
- [Fake Sleep](#-fake-sleep)
- [Result](#-result)
- [Artisan Commands](#-artisan-commands)
    - [make:action](#makeaction)
    - [Database Backups](#database-backups)
    - [translations:extract](#translationsextract)
- [GitHub Issue Logger](#-github-issue-logger)
- [Credits](#credits)
- [License](#license)

### ✅ Strict Models

[](#-strict-models)

Improves how Eloquent handles undefined attributes, lazy loading, and invalid assignments.

- Accessing a missing attribute throws an error.
- Lazy loading is blocked unless explicitly allowed.
- Setting undefined attributes throws instead of failing silently.

**Why:** Avoids subtle bugs and makes model behavior easier to reason about.

---

### ⚡️ Auto Eager Loading

[](#️-auto-eager-loading)

Automatically eager loads relationships defined in the model's `$with` property.

**Why:** Reduces N+1 query issues and improves performance without needing `with()` everywhere.

---

### 🔓 Optional Unguarded Models

[](#-optional-unguarded-models)

Disables Laravel's mass assignment protection globally (opt-in).

**Why:** Useful in trusted or local environments where you want to skip defining `$fillable`.

---

### 🕒 Immutable Dates

[](#-immutable-dates)

Uses `CarbonImmutable` instead of mutable date objects across your app.

**Why:** Prevents unexpected date mutations and improves predictability.

---

### 🔒 Force HTTPS

[](#-force-https)

Forces all generated URLs to use `https://`.

**Why:** Ensures all traffic uses secure connections by default.

---

### 🛑 Safe Console

[](#-safe-console)

Blocks potentially destructive Artisan commands in production (e.g., `migrate:fresh`).

**Why:** Prevents accidental data loss and adds a safety net in sensitive environments.

---

### 🔄 Prevent Stray Requests

[](#-prevent-stray-requests)

Configures Laravel Http Facade to prevent stray requests.

**Why:** Ensure every HTTP calls during tests have been explicitly faked.

---

### 😴 Fake Sleep

[](#-fake-sleep)

Configures Laravel Sleep Facade to be faked.

**Why:** Avoid unexpected sleep during testing cases.

---

### 📦 Result

[](#-result)

A small, framework-agnostic **success/failure** wrapper for service and action outcomes. Expected business failures are modeled as **PHP enums**, not thrown exceptions — so invalid email, duplicate records, and similar cases stay explicit and easy to branch on.

**Namespace:** `IvanFuhr\Essentials\Result\Result`

No configuration or service provider setup is required. Composer autoloads the class and registers global helpers immediately (no service provider).

**PHPStan generics:** annotate actions with `@return Result` (or the native return type stays `Result` and the PHPDoc carries the types). After `successful()` / `failed()`, `value()` and `failure()` are narrowed to the success value and failure enum respectively.

#### Defining failure enums

[](#defining-failure-enums)

```
enum CreateUserError
{
    case InvalidEmail;
    case EmailAlreadyExists;
}
```

Use a dedicated enum per use case (or domain area). Backed enums (`string` or `int`) work well when you need stable codes for APIs or translations.

#### Creating results

[](#creating-results)

Global helpers are available as soon as the package is installed:

```
// Success with a value (any type)
$result = success($user);

// Failure with an enum case
$result = fail(CreateUserError::InvalidEmail);
```

You can also use the class directly:

```
use IvanFuhr\Essentials\Result\Result;

$result = Result::success($user);
$result = Result::fail(CreateUserError::InvalidEmail);
```

> **Note:** The `fail()` helper and `Result::fail()` factory exist because PHP does not allow a static `failure()` factory and an instance `failure()` getter on the same class. The getter returns the enum case: `$result->failure()`.

#### Checking state

[](#checking-state)

MethodDescription`successful()``true` when the result holds a success value`failed()``true` when the result holds a failure enum`value()`Returns the success value (call only when `successful()` is `true`)`valueOr($default)`Returns the success value, or `$default` on failure`failure()`Returns the failure `UnitEnum` (call only when `failed()` is `true`)Prefer `whenSuccessful()` / `whenFailed()` for branching. Use `value()` and `failure()` after checking state, or `valueOr()` when a default is enough.

```
if ($result->successful()) {
    $user = $result->value();
}

$guest = $result->valueOr(null);

if ($result->failed()) {
    $error = $result->failure(); // CreateUserError enum case
}
```

#### Fluent handling

[](#fluent-handling)

Chain handlers on the same result. Only the **first matching** handler runs; later handlers are skipped until you start a new chain.

MethodDescription`whenSuccessful(callable $callback)`Runs only on success; receives the value`whenFailed(UnitEnum $expectedFailure, callable $callback)`Runs only when the failure enum equals `$expectedFailure` (`===`)`otherwise(callable $callback)`Runs only if no earlier handler matchedTypical usage in a controller or action:

```
enum CreateUserError
{
    case InvalidEmail;
    case EmailAlreadyExists;
}

return $this->createUser->handle($email)
    ->whenSuccessful(fn (User $user) => redirect()->route('users.show', $user))
    ->whenFailed(CreateUserError::InvalidEmail, fn () => back()->withErrors(['email' => 'Invalid email.']))
    ->whenFailed(CreateUserError::EmailAlreadyExists, fn () => back()->withErrors(['email' => 'Email already in use.']))
    ->otherwise(fn () => abort(500));
```

Service returning a `Result`:

```
final readonly class CreateUser
{
    public function handle(string $email): Result
    {
        if (! filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return fail(CreateUserError::InvalidEmail);
        }

        if (User::query()->where('email', $email)->exists()) {
            return fail(CreateUserError::EmailAlreadyExists);
        }

        return success(User::create(['email' => $email]));
    }
}
```

**Why:** Keeps happy paths and expected failures explicit, improves testability, and avoids `try/catch` for business rules that are not exceptional.

**Tips:**

- `Result::fail()` only accepts `UnitEnum` — define one enum per operation or bounded context.
- `whenFailed()` compares enum cases with `===`; pass the same case you used in `Result::fail()`.
- Use `otherwise()` for unhandled enum cases (e.g. a new case you have not mapped yet).
- Handlers are for side effects (redirects, logging, mapping to HTTP). Use `value()` / `failure()` when you need the payload after checking `successful()` / `failed()`.

---

### 🏗️ Artisan Commands

[](#️-artisan-commands)

#### `make:action`

[](#makeaction)

Quickly generates action classes in your Laravel application:

```
php artisan make:action CreateUserAction
```

This creates a clean action class at `app/Actions/CreateUserAction.php`:

```
