PHPackages                             internetguru/laravel-common - 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. internetguru/laravel-common

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

internetguru/laravel-common
===========================

v5.18.13(1mo ago)04.7k↓68.9%4PHPCI passing

Since Sep 12Pushed 1mo ago2 watchersCompare

[ Source](https://github.com/internetguru/laravel-common)[ Packagist](https://packagist.org/packages/internetguru/laravel-common)[ RSS](/packages/internetguru-laravel-common/feed)WikiDiscussions main Synced 2w ago

READMEChangelogDependencies (74)Versions (235)Used By (4)

Laravel Common
==============

[](#laravel-common)

> This package provides handy utilities for Laravel applications.

BranchStatusCode CoverageMain[![tests](https://github.com/internetguru/laravel-common/actions/workflows/phpunit.yml/badge.svg?branch=main)](https://github.com/internetguru/laravel-common/actions/workflows/phpunit.yml/badge.svg?branch=main)[![coverage](https://raw.githubusercontent.com/internetguru/laravel-common/refs/heads/badges/main-coverage.svg)](https://raw.githubusercontent.com/internetguru/laravel-common/refs/heads/badges/main-coverage.svg)Staging[![tests](https://github.com/internetguru/laravel-common/actions/workflows/phpunit.yml/badge.svg?branch=staging)](https://github.com/internetguru/laravel-common/actions/workflows/phpunit.yml/badge.svg?branch=staging)[![coverage](https://raw.githubusercontent.com/internetguru/laravel-common/refs/heads/badges/staging-coverage.svg)](https://raw.githubusercontent.com/internetguru/laravel-common/refs/heads/badges/staging-coverage.svg)Dev[![tests](https://github.com/internetguru/laravel-common/actions/workflows/phpunit.yml/badge.svg?branch=dev)](https://github.com/internetguru/laravel-common/actions/workflows/phpunit.yml/badge.svg?branch=dev)[![coverage](https://raw.githubusercontent.com/internetguru/laravel-common/refs/heads/badges/dev-coverage.svg)](https://raw.githubusercontent.com/internetguru/laravel-common/refs/heads/badges/dev-coverage.svg)Table of Contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Run Tests Locally](#run-tests-locally)
- [E2E Tests](#e2e-tests)
- [Service Providers](#service-providers)
    - [CommonServiceProvider](#commonserviceprovider)
    - [ReadOnlyServiceProvider](#readonlyserviceprovider)
    - [TranslationServiceProvider](#translationserviceprovider)
- [Middleware](#middleware)
    - [CheckPostItemNames](#checkpostitemnames-middleware)
    - [InjectMetaRobots](#injectmetarobots-middleware)
    - [InjectUmamiScript](#injectumamiscript-middleware)
    - [PreventDuplicateSubmissions](#preventduplicatesubmissions-middleware)
    - [SetPrevPage](#setprevpage-middleware)
    - [TimezoneMiddleware](#timezonemiddleware)
    - [VerifyCsrfToken](#verifycsrftoken)
- [Helper Methods](#helper-methods)
- [Helper Macros](#helper-macros)
- [Blade Components](#blade-components)
    - [Breadcrumb](#breadcrumb-blade-component)
    - [System Messages (Livewire)](#system-messages-livewire-component)
    - [Form &amp; Inputs](#form-blade-components)
    - [Language Switch](#language-switch-blade-component)
    - [Print Button](#print-button-blade-component)
    - [Footer Copy](#footer-copy-blade-component)
    - [Demo Info](#demo-info-blade-component)
    - [Read-Only Mode Info](#read-only-mode-info-blade-component)
    - [Email Feedback](#email-feedback-blade-component)
    - [Editable](#editable-blade-component)
    - [Admin Button Text](#admin-button-text-blade-component)
    - [Association History](#association-history-blade-component)
    - [Component Signatures](#component-signatures-blade-component)
- [Casts](#casts)
    - [CarbonIntervalCast](#carbonintervalcast)
- [Traits](#traits)
    - [Ulid32 Trait](#ulid32-trait)
- [Rules](#rules)
    - [Ulid32 Validation Rule](#ulid32-validation-rule)
- [Services](#services)
    - [GeolocationService](#geolocationservice)
- [Notifications](#notifications)
    - [BaseNotification](#basenotification)
    - [MailMessage](#mailmessage)
    - [Mail Logging](#mail-logging)
- [Exception Handling](#exception-handling)
- [Logging](#logging)
    - [JsonDailyLogger](#jsondailylogger)
- [Localization](#localization)
- [Publishing Assets](#publishing-assets)

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

[](#installation)

You can install the package via Composer:

```
composer require internetguru/laravel-common
```

The `CommonServiceProvider` is auto-discovered via `composer.json` `extra.laravel.providers`. No manual registration is needed for the core provider.

Run Tests Locally
-----------------

[](#run-tests-locally)

To run the tests manually, you can use the following command:

```
./test.sh
```

E2E Tests
---------

[](#e2e-tests)

The package ships reusable [Playwright](https://playwright.dev/) test helpers in `tests/e2e/common-tests.js`. Consuming projects can register them into their own test suite with a single call.

### Setup

[](#setup)

1. Install Playwright in your project if not already present:

    ```
    npm init playwright@latest
    ```
2. In your test file, import and register the helpers:

    ```
    import { test, expect } from '@playwright/test';
    import { registerCommonTests } from '../../vendor/internetguru/laravel-common/tests/e2e/common-tests.js';

    registerCommonTests(test, expect, {
      languages: { en: 'English', cs: 'Česky' },
      demo: process.env.APP_DEMO === 'true',
    });
    ```

### Options

[](#options)

OptionTypeDefaultDescription`languages``object``{ en: 'English', cs: 'Česky' }`Language code → label map. Language switch tests are skipped when only one language is configured.`demo``boolean``false`When `true`, includes a test verifying the demo mode banner is visible.### Covered test groups

[](#covered-test-groups)

GroupWhat is tested`layout``header`, `main`, `footer` presence; `charset`, `viewport`, and `title` meta tags.`breadcrumb`Visibility, item count, active state, growth on subpages.`language switch`Visibility, correct item count, active highlight, language change, persistence across pages. *(skipped when `languages` has one entry)*`error pages`401, 403, 404, 500, 503 status codes and `h1` content; error index links; unknown code falls back to 404.`messages``.messages-wrapper` is present on every page.`demo mode`Demo banner visible. *(skipped unless `demo: true`)*`csrf`CSRF token meta tag is present and non-empty.`i18n pages``/i18n`, `/i18n/complete`, `/i18n/missing-all`, `/i18n/missing-cs`, `/i18n/missing-en` all load.`html structure``` attribute is set; exactly one `` per page.Service Providers
-----------------

[](#service-providers)

### CommonServiceProvider

[](#commonserviceprovider)

Auto-registered via package discovery. It provides:

- Custom [exception handler](#exception-handling) registration.
- Loading of package routes, views (`ig-common` namespace), translations, and Blade components (`ig` namespace).
- Registration of the [Livewire Messages](#system-messages-livewire-component) component.
- Listener for [mail logging](#mail-logging) (`NotificationSent` event).
- Registration of the [`ulid32` validation rule](#ulid32-validation-rule).
- Registration of all [helper macros](#helper-macros) (String, Number, Carbon).
- Automatic registration of all [middleware](#middleware) into the `web` middleware group.
- Queue connection safety check — throws an exception at boot if the queue connection is set to `sync` (except during unit tests).

### ReadOnlyServiceProvider

[](#readonlyserviceprovider)

> Intercepts all write database queries and throws `DbReadOnlyException` when `config('app.readonly')` is `true`.

Read-only operations (`SELECT`, `SHOW`, `DESCRIBE`, `EXPLAIN`, `PRAGMA`) are always allowed. Queries targeting `sessions`, `pin_logins`, `mail_logs`, `users`, and `socialites` tables are whitelisted.

To use, register the provider in your `config/app.php`:

```
'providers' => ServiceProvider::defaultProviders()->merge([
    InternetGuru\LaravelCommon\ReadOnlyServiceProvider::class,
])->toArray(),
```

Then set `readonly` to `true` in `config/app.php` (or via environment variable) to activate read-only mode.

### TranslationServiceProvider

[](#translationserviceprovider)

> Logs missing translations and translation variables in the current language. Throws an exception when not in production environment. In debug mode, checks all available languages.

- **Logs warning** when a translation key is missing or a variable required in a translation string is not provided.
- **Checks all languages** in debug mode from all available locales.
- **Throws exception** `InternetGuru\LaravelCommon\Exceptions\TranslatorException` instead of logging when the app is not in production mode.

To use the provider, replace the default `TranslationServiceProvider` in `config/app.php`:

```
use Illuminate\Support\ServiceProvider;

'providers' => ServiceProvider::defaultProviders()->replace([
    Illuminate\Translation\TranslationServiceProvider::class => InternetGuru\LaravelCommon\TranslationServiceProvider::class,
])->toArray(),
```

Middleware
----------

[](#middleware)

All middleware listed below is automatically registered in the `web` middleware group by the `CommonServiceProvider`. No manual registration is needed.

To bypass a specific middleware on a route, use the `withoutMiddleware` method:

```
Route::get('/example', ExampleController::class)
    ->withoutMiddleware(\InternetGuru\LaravelCommon\Http\Middleware\PreventDuplicateSubmissions::class);
```

### `CheckPostItemNames` Middleware

[](#checkpostitemnames-middleware)

> Checks for invalid POST parameter names containing dots `"."`. Helps prevent issues with Laravel's input handling. Throws an exception in non-production environments and logs a warning in production.

Example:

- When a POST request contains parameter names with dots:

    ```
    POST /submit-form
    Content-Type: application/x-www-form-urlencoded

    username=johndoe&user.email=johndoe@example.com
    ```
- **In Non-Production Environments**: The middleware will throw an HTTP 400 exception:

    ```
    Invalid POST parameter names containing dots: user.email

    ```
- **In Production Environment**: The middleware will log a warning:

    ```
    [WARNING] Invalid POST parameter names containing dots: user.email

    ```

### `InjectMetaRobots` Middleware

[](#injectmetarobots-middleware)

> Automatically injects a `` tag into HTML responses before `` when `META_ROBOTS` is set.

Set the following environment variable to enable:

VariableDescriptionDefault`META_ROBOTS`Robots directive (e.g. `noindex`, `noindex,nofollow`).`null` (disabled)Example `.env`:

```
META_ROBOTS=noindex,nofollow
```

The injected tag:

```

```

### `InjectUmamiScript` Middleware

[](#injectumamiscript-middleware)

> Automatically injects the [Umami](https://umami.is/) analytics tracking script into HTML responses when `UMAMI_WEBSITE_ID` is set.

The script is injected before the closing `` tag. Set the following environment variables to enable:

VariableDescriptionDefault`UMAMI_WEBSITE_ID`Your Umami website ID (required to enable tracking).`''` (disabled)`UMAMI_SRC`URL to the Umami tracking script.`https://umami.internetguru.io/script.js``UMAMI_IDENTIFY`Send user identity data (`id`, `user_type`, optional `user_role`) on page load.`true``UMAMI_IDENTIFY_HASH`Hash the user ID with SHA-256 before sending.`false`Example `.env`:

```
UMAMI_WEBSITE_ID=0d38f931-afdc-4a99-a913-5c601fc95629
```

The injected script:

```

```

### `PreventDuplicateSubmissions` Middleware

[](#preventduplicatesubmissions-middleware)

> Prevents duplicate POST form submissions by caching a hashed request fingerprint (IP + path + input minus reCAPTCHA) for 1 minute. Livewire update requests are excluded.

When a duplicate submission is detected, the user is redirected back with input and an error message.

### `SetPrevPage` Middleware

[](#setprevpage-middleware)

> Tracks the current and previous page URLs in the session for GET requests. Used internally by the exception handler to redirect users back to meaningful pages on errors.

Ignores AJAX requests and image (`img/*`) requests. Prevents tracking the same URL consecutively.

### `TimezoneMiddleware`

[](#timezonemiddleware)

> Detects the user's timezone via IP geolocation and stores it in the session as `display_timezone`.

Uses the [GeolocationService](#geolocationservice) to resolve the IP address. Falls back to `config('geoip.default_location.timezone')` on failure. Resolves only once per session.

### `VerifyCsrfToken`

[](#verifycsrftoken)

> Extends Laravel's CSRF verification with HMAC-based request signature verification. Requests containing a valid `X-Signature` and `X-Timestamp` header pair bypass CSRF checks. Livewire routes are also excluded by default.

The signature is validated using the app key with a 60-second freshness window.

Helper Methods
--------------

[](#helper-methods)

> The `Helpers` class provides useful static methods for Laravel applications.

Configuration and example usage:

1. Add the following lines to `config/app.php`:

    ```
    use Illuminate\Support\Facades\Facade;

    'aliases' => Facade::defaultAliases()->merge([
        'Helpers' => InternetGuru\LaravelCommon\Support\Helpers::class,
    ])->toArray(),
    ```
2. Use `Helpers` class methods in your application:

    ```

    ```

Available methods:

MethodDescription`getAppInfoArray()`Returns app name, environment, version, git branch, and commit as an array.`getAppInfo()`Returns app info as a single string.`parseUrlPath($homeRoute, $skipFirst)`Parses the current URL path into breadcrumb segments with translations.`createTitle($separator, $homeRoute)`Generates a page title from breadcrumb segments (reversed, separated).`getEmailClientLink()`Returns a link to the Mailpit inbox when using Mailpit mailer.`verifyRequestSignature(Request $request)`Verifies HMAC-SHA256 request signature (`X-Signature` + `X-Timestamp` headers).For full implementation details, see the [Helpers](src/Support/Helpers.php) class.

Helper Macros
-------------

[](#helper-macros)

> The package registers a set of useful macros for `Str`, `Carbon`, and `Number`. See [macros.php](src/Support/macros.php) for the complete list.

### String Macros

[](#string-macros)

MacroDescription`Str::ref($length)`Generates a random alphanumeric reference code (excludes ambiguous characters `i`, `l`, `o`, `0`, `1`, `u`). Starts with a letter and contains at least one digit.### Number Macros

[](#number-macros)

MacroDescription`Number::currencyForHumans($number, $in, $precision)`Formats a number as a locale-aware currency string. Returns the currency symbol if no number is provided.`Number::formatCurrencyToInput($number, $in, $precision, $inputTemplate)`Formats a number for use inside an input field with a currency symbol.### Carbon Macros

[](#carbon-macros)

MacroDescription`$date->dateForHumans()`Locale-aware date (`L` format).`$date->dateTimeForHumans()`Locale-aware date and time (`L LT` format).`$date->myDiffForHumans()`Human-readable time difference with "just now" for &lt;60 seconds and "1 year" normalization.`$date->timeForHumans()`Clean time format (removes leading zeros and `:00`).`$date->toDisplayTimezone()`Converts the date to the user's display timezone stored in the session (`display_timezone`), falling back to `config('app.timezone')`.`$date->randomWorkTime($from, $to)`Sets a random time during work hours (default 9–17).Example usage:

```
use Carbon\Carbon;
use Illuminate\Support\Facades\Number;
use Illuminate\Support\Str;

echo Str::ref(6);
// Output: "k3mhpq"

Number::useCurrency('USD');
echo Number::currencyForHumans(1234);
// Output (en_US locale): $1,234
echo Number::currencyForHumans();
// Output (en_US locale): $
echo Number::currencyForHumans(1234.567, in: 'EUR', precision: 2);
// Output (en_US locale): €1,234.57

$date = Carbon::parse('2023-12-31');
echo $date->dateForHumans();
// Output (en_US locale): 12/31/2023
$dateTime = Carbon::parse('2023-12-31 18:30:00');
echo $dateTime->dateTimeForHumans();
// Output (en_US locale): 12/31/2023 6:30 PM
```

Blade Components
----------------

[](#blade-components)

All Blade components are registered under the `ig` namespace and can be used with ``.

### Breadcrumb Blade Component

[](#breadcrumb-blade-component)

> Renders breadcrumb navigation based on routes matching the current URL segments. Supports translations with short and long labels, custom divider, and segment skipping.

Key Features:

- **Customizable Divider** – Allows a custom divider symbol between breadcrumb items.
- **Short and Long Labels** – Using `trans_choice` if available shows n-th right translation based on the item position.
- **Segment Skipping** – Skips a specified number of URL segments. Useful for nested routes or routes with prefixes (e.g. language).
- **Skip Prefixes** – Routes whose URI starts with a configured prefix are treated as error pages (no breadcrumb generated), preventing missing translation warnings. Configured via `breadcrumb_skip_prefixes` in `config/ig-common.php`:

    ```
    'breadcrumb_skip_prefixes' => [
        '_debugbar',
        '_ignition',
        'livewire',
        'storage',
        'telescope',
        'horizon',
    ],
    ```

Usage:

```

```

Example:

- Assuming you have the following routes defined: ```
