Search by

sebastiansulinski / laravel-bits

sebastiansulinski

A set of handy utilities for any Laravel project.

Package info

github.com/sebastiansulinski/laravel-bits

Type:project

pkg:composer/sebastiansulinski/laravel-bits

Statistics

Installs: 430

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.5.3 2026-09-22 13:49 UTC

README

A set of handy utilities for any Laravel project.

Requirements

  • PHP ^8.4
  • Laravel ^12.0 || ^13.0

Installation

You can install the package via Composer:

composer require sebastiansulinski/laravel-bits

The package will automatically register its service provider.

Configuration

The package ships with a configuration file, which you can publish if you need to change any of its defaults:

php artisan vendor:publish --tag=laravel-bits

strict_models

Controls whether the package puts Eloquent into strict mode on boot - preventLazyLoading, preventSilentlyDiscardingAttributes and preventAccessingMissingAttributes.

'strict_models' => env('LARAVEL_BITS_STRICT_MODELS', null),

Unset - which is the default - keeps the behaviour the package has always had: strict mode is on in every environment the application does not report as production. Nothing changes unless you set the key.

That reading comes from the application rather than from the APP_ENV variable, so Artisan's --env flag still moves it exactly as it always did. Resolving the default in the configuration file instead would quietly break that, which is why an unset key defers the decision to boot.

Overriding with an environment variable

LARAVEL_BITS_STRICT_MODELS=false

Values Laravel resolves to false, 0 or an empty string turn strict mode off, and anything else counts as true, so a malformed value fails towards strict rather than silently relaxing the checks. null is the exception: it reads as unset, and the package goes back to deciding at boot.

Overriding in the configuration file

Applications with a production equivalent environment under a different name - user acceptance testing, for instance - should set this explicitly. Without it, that environment ends up stricter than production, which is exactly the divergence a production equivalent environment is meant to avoid.

// config/laravel-bits.php

'strict_models' => ! in_array(env('APP_ENV', 'production'), ['production', 'uat'], true),

Configuration files are loaded before the application resolves its own environment, so an expression written there reads the APP_ENV variable and will not follow --env. Where that matters, set the key from a service provider instead - every register method runs before this package boots:

public function register(): void
{
    config()->set(
        'laravel-bits.strict_models',
        ! in_array($this->app->environment(), ['production', 'uat'], true)
    );
}

Available Traits

EnhancedEnums

The EnhancedEnums trait provides additional utility methods for PHP enums, making them more convenient to work with in Laravel applications.

Usage

use LaravelBits\Traits\EnhancedEnums;

enum Status: string
{
    use EnhancedEnums;

    case Active = 'active';
    case Pending = 'pending';
    case Closed = 'closed';

    public function label(): string
    {
        return ucfirst($this->value) . ' Status';
    }
}

Available Methods

  • values(?array $cases = null): array - Get array of enum values
  • names(?array $cases = null): array - Get array of enum names
  • options(?array $cases = null): array - Get array of name/value pairs
  • toArray(): array - Convert enum instance to array
  • label(): string - Get label for enum case (can be overridden)
  • except(array|self $cases): array - Exclude certain cases from enum
  • collection(): Collection - Get cases as Laravel Collection

Examples

// Get all values
Status::values(); // ['active', 'pending', 'closed']

// Get all names
Status::names(); // ['Active', 'Pending', 'Closed']

// Get options for dropdowns
Status::options();
// [
//     ['name' => 'Active Status', 'value' => 'active'],
//     ['name' => 'Pending Status', 'value' => 'pending'],
//     ['name' => 'Closed Status', 'value' => 'closed']
// ]

// Convert single case to array
Status::Active->toArray(); // ['name' => 'Active Status', 'value' => 'active']

// Exclude certain cases
Status::except([Status::Active, Status::Closed]); // Only Pending case

// Get as Collection
Status::collection(); // Collection of all cases

Serialisable

The Serialisable trait provides JSON serialization capabilities for any class.

Usage

use LaravelBits\Traits\Serialisable;

class MyClass
{
    use Serialisable;

    public function toArray(): array
    {
        return [
            'property1' => $this->property1,
            'property2' => $this->property2,
        ];
    }
}

Available Methods

  • __toString(): string - Convert object to JSON string
  • toJson($options = 0): string - Get JSON representation of the object
  • toArray(): array - Abstract method that must be implemented

Examples

$object = new MyClass();

// Convert to JSON string
echo $object; // Calls __toString() which returns JSON

// Get JSON with options
$json = $object->toJson(JSON_PRETTY_PRINT);

Sortable

The Sortable trait provides utilities for handling sortable records with automatic sort position management.

Usage

use LaravelBits\Traits\Sortable;

class MySortableService
{
    use Sortable;
    
    public function sort(array $ids): void
    {
        MyModel::upsert(
            $this->sortablePayload($ids), 'ulid', ['sort']
        );
    }

    protected function existingSortables(array $ids): Collection
    {
        return MyModel::whereIn('ulid', $ids)->get();
    }

    protected function sortableModelColumns(): array
    {
        return ['ulid', 'name', 'description'];
    }
}

Sorter

The Sorter and SorterPayload classes provide a powerful way to reorder records based on a new sequence of IDs while maintaining proper sort values. This is particularly useful for drag-and-drop interfaces or any scenario where you need to update the sort order of multiple records efficiently.

SorterPayload

The SorterPayload class prepares a collection of models in the desired order based on an array of IDs.

Constructor Parameters:

  • $models - Collection of Eloquent models to be reordered
  • $ids - Array of IDs in the desired order
  • $filter - String column name or Closure to match models with IDs (defaults to 'id')

Sorter

The Sorter class generates update sets for bulk database operations based on the reordered payload.

Constructor Parameters:

  • $payload - SorterPayload instance with reordered records
  • $idColumn - Column name used as the primary key (defaults to 'id'). When used in combination with Eloquent Builder::updateMany(), this should match the first argument $caseColumn.
  • $sortColumn - Column name used for sorting (defaults to 'sort')
  • $updateColumn - Column name to update (defaults to 'sort')

Methods:

  • getSet(?Closure $callback = null): UpdateManySet - Generate an UpdateManySet for bulk updates

Usage Examples

Basic Sorting:

use LaravelBits\Utilities\Sorter\Sorter;
use LaravelBits\Utilities\Sorter\SorterPayload;

// Get your models
$models = Book::where('category_id', 1)->get();

// Define the new order using IDs
$newOrder = [3, 1, 4, 2, 5]; // Book IDs in desired order

// Create the payload
$payload = new SorterPayload(
    models: $models,
    ids: $newOrder,
    filter: 'id' // Match by 'id' column
);

// Create the sorter
$sorter = new Sorter(payload: $payload);

// Get the update set and apply it
$updateSet = $sorter->getSet();
Book::updateMany('id', $updateSet);

Advanced Sorting with Custom Columns:

// Using ULID as identifier and custom sort column
$models = Product::where('active', true)->get();
$ulidOrder = ['01H123...', '01H456...', '01H789...']; // ULIDs in desired order

$payload = new SorterPayload(
    models: $models,
    ids: $ulidOrder,
    filter: fn($model, $ulid) => $model->ulid->toString() === $ulid
);

$sorter = new Sorter(
    payload: $payload,
    idColumn: 'id',
    sortColumn: 'position',
    updateColumn: 'position'
);

$updateSet = $sorter->getSet();
Product::updateMany('id', $updateSet);

Custom Value Generation:

// Generate custom values with a callback
$sorter = new Sorter(
    payload: $payload,
    updateColumn: 'display_name'
);

$updateSet = $sorter->getSet(
    fn($model, $index, $sort) => "Item #{$index} (Sort: {$sort})"
);

Product::updateMany('id', $updateSet);

The callback function receives three parameters:

  • $model - The current Eloquent model
  • $index - Zero-based index in the reordered sequence
  • $sort - The calculated sort value for this position

Available Macros

QueryBuilder whereDateBetween

Adds a whereDateBetween method to Laravel's Query Builder for filtering records between two dates.

Usage

use Illuminate\Support\Facades\DB;

// Filter records between two dates
DB::table('orders')
    ->whereDateBetween('created_at', ['2024-01-01', '2024-12-31'])
    ->get();

// With custom boolean operator
DB::table('orders')
    ->where('status', 'active')
    ->whereDateBetween('created_at', ['2024-01-01', '2024-12-31'], 'or')
    ->get();

Parameters

  • $column - The column name to filter
  • $dates - Array with two dates [start_date, end_date]
  • $boolean - Boolean operator ('and' or 'or'), defaults to 'and'

QueryBuilder whereLowercase

Adds a whereLowercase method to Laravel's Query Builder for comparing a column against a lowercased value. Works with both Query Builder and Eloquent Builder. Accepts the same arguments as the where method.

Usage

use Illuminate\Support\Facades\DB;

// Simple equality check - lowercases the value automatically
DB::table('users')
    ->whereLowercase('email', 'John@Example.COM')
    ->get();
// Equivalent to: ->where('email', 'john@example.com')

// With Eloquent
User::query()
    ->whereLowercase('email', $request->email)
    ->first();

// With a custom operator
User::query()
    ->whereLowercase('email', '!=', 'ADMIN@EXAMPLE.COM')
    ->get();

// With boolean operator
User::query()
    ->where('name', 'John')
    ->whereLowercase('email', '=', 'JANE@EXAMPLE.COM', 'or')
    ->get();

Parameters

  • $column - The column name to filter
  • $operator - Comparison operator (defaults to '=') or the value when using 2-argument form
  • $value - The value to lowercase and compare against
  • $boolean - Boolean operator ('and' or 'or'), defaults to 'and'

EloquentBuilder updateMany

Adds an updateMany method to Laravel's Eloquent Builder for efficiently updating multiple records with different values in a single query.

Usage

use App\Models\Book;
use LaravelBits\Data\UpdateManySet;

// Update multiple records with different sort values
Book::updateMany('id', new UpdateManySet('sort', [
    1 => 30,
    2 => 20,
    3 => 10,
]));

// Update multiple columns at once
Book::updateMany('id', [
    new UpdateManySet('sort', [1 => 30, 2 => 20, 3 => 10]),
    new UpdateManySet('priority', [1 => 'high', 2 => 'medium', 3 => 'low']),
]);

// With custom timestamp
Book::updateMany('id', new UpdateManySet('sort', [
    1 => 30,
    2 => 20,
    3 => 10,
]), now()->addHour());

Parameters

  • $caseColumn - The column to match against (usually 'id')
  • $sets - UpdateManySet instance or array of UpdateManySet instances
  • $timestamp - Optional timestamp for updated_at (defaults to now())

Benefits

  • Performance: Updates multiple records in a single SQL query using CASE statements
  • Efficiency: Avoids N+1 query problems when updating many records
  • Automatic timestamps: Automatically updates the updated_at column

Available Casts

Lowercase

The Lowercase cast automatically converts string values to lowercase when getting and setting model attributes. This is useful for normalizing data like email addresses.

Usage

use Illuminate\Database\Eloquent\Model;
use LaravelBits\Casts\Lowercase;

class User extends Model
{
    protected function casts(): array
    {
        return [
            'email' => Lowercase::class,
        ];
    }
}

Examples

$user = new User(['email' => 'JOHN@EXAMPLE.COM']);
$user->email; // 'john@example.com'

$user->email = 'Jane@Example.COM';
$user->email; // 'jane@example.com'

// Null values are preserved
$user->email = null;
$user->email; // null

License

This package is open-sourced software licensed under the MIT license.

Contributing

Please see CONTRIBUTING for details.

Credits