internetguru / laravel-common
Installs: 3 410
Dependents: 5
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 0
Open Issues: 0
pkg:composer/internetguru/laravel-common
Requires
- darvis/livewire-injection-stopper: ^1.2
- internetguru/laravel-recaptchav3: ^1.0
- laravel/framework: ^10.0 || ^11.0
- livewire/livewire: ^3.6
- spatie/laravel-ignition: ^2.9
- torann/geoip: ^3.0
Requires (Dev)
- laravel/pint: ^1.25
- livewire/livewire: ^3.6
- orchestra/testbench: ^9.5
- phpunit/php-code-coverage: ^11.0
- dev-main
- v5.1.0
- v5.0.0
- v4.8.6
- v4.8.5
- v4.8.4
- v4.8.3
- v4.8.2
- v4.8.1
- v4.8.0
- v4.7.6
- v4.7.5
- v4.7.4
- v4.7.3
- v4.7.2
- v4.7.1
- v4.7.0
- v4.6.4
- v4.6.3
- v4.6.2
- v4.6.1
- v4.6.0
- v4.5.2
- v4.5.1
- v4.5.0
- v4.4.9
- v4.4.8
- v4.4.7
- v4.4.6
- v4.4.5
- v4.4.4
- v4.4.3
- v4.4.2
- v4.4.1
- v4.4.0
- v4.3.0
- v4.2.8
- v4.2.7
- v4.2.6
- v4.2.5
- v4.2.4
- v4.2.3
- v4.2.2
- v4.2.1
- v4.2.0
- v4.1.1
- v4.1.0
- v4.0.0
- v3.0.0
- v2.17.2
- v2.17.1
- v2.17.0
- v2.16.7
- v2.16.6
- v2.16.5
- v2.16.4
- v2.16.3
- v2.16.2
- v2.16.1
- v2.16.0
- v2.15.3
- v2.15.2
- v2.15.1
- v2.15.0
- v2.14.2
- v2.14.1
- v2.14.0
- v2.13.0
- v2.12.6
- v2.12.5
- v2.12.4
- v2.12.3
- v2.12.2
- v2.12.1
- v2.12.0
- v2.11.1
- v2.11.0
- v2.10.2
- v2.10.1
- v2.10.0
- v2.9.0
- v2.8.8
- v2.8.7
- v2.8.6
- v2.8.5
- v2.8.4
- v2.8.3
- v2.8.2
- v2.8.1
- v2.8.0
- v2.7.1
- v2.7.0
- v2.6.2
- v2.6.1
- v2.6.0
- v2.5.1
- v2.5.0
- v2.4.2
- v2.4.1
- v2.4.0
- v2.3.2
- v2.3.1
- v2.3.0
- v2.2.3
- v2.2.2
- v2.2.1
- v2.2.0
- v2.1.1
- v2.1.0
- v2.0.5
- v2.0.4
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- v0.14.3
- v0.14.2
- v0.14.1
- v0.14.0
- v0.13.2
- v0.13.1
- v0.13.0
- v0.12.1
- v0.12.0
- v0.11.2
- v0.11.1
- v0.11.0
- v0.10.2
- v0.10.1
- v0.10.0
- v0.9.0
- v0.8.2
- v0.8.1
- v0.8.0
- v0.7.11
- v0.7.10
- v0.7.9
- v0.7.8
- v0.7.7
- v0.7.6
- v0.7.5
- v0.7.4
- v0.7.3
- v0.7.2
- v0.7.1
- v0.7.0
- v0.6.3
- v0.6.2
- v0.6.1
- v0.6.0
- v0.5.4
- v0.5.3
- v0.5.2
- v0.5.1
- v0.5.0
- v0.4.7
- v0.4.6
- v0.4.5
- v0.4.4
- v0.4.3
- v0.4.2
- v0.4.1
- v0.4.0
- v0.3.1
- v0.3.0
- v0.2.0
- v0.1.0
- dev-dev
- dev-main-5
- dev-staging
- dev-main-4
- dev-main-3
- dev-main-2
- dev-main-1
- dev-main-0
This package is auto-updated.
Last update: 2026-02-25 21:09:30 UTC
README
This package provides handy utilities for Laravel applications.
| Branch | Status | Code Coverage |
|---|---|---|
| Main | ||
| Staging | ||
| Dev |
Table of Contents
- Installation
- Run Tests Locally
- Service Providers
- Middleware
- Helper Methods
- Helper Macros
- Blade Components
- Casts
- Traits
- Rules
- Services
- Notifications
- Exception Handling
- Logging
- Localization
- Publishing Assets
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
To run the tests manually, you can use the following command:
./test.sh
Service Providers
CommonServiceProvider
Auto-registered via package discovery. It provides:
- Custom exception handler registration.
- Loading of package routes, views (
ig-commonnamespace), translations, and Blade components (ignamespace). - Registration of the Livewire Messages component.
- Listener for mail logging (
NotificationSentevent). - Registration of the
ulid32validation rule. - Registration of all helper macros (String, Number, Carbon).
- Automatic registration of all middleware into the
webmiddleware group. - Queue connection safety check — throws an exception at boot if the queue connection is set to
sync(except during unit tests).
ReadOnlyServiceProvider
Intercepts all write database queries and throws
DbReadOnlyExceptionwhenconfig('app.readonly')istrue.
Read-only operations (SELECT, SHOW, DESCRIBE, EXPLAIN, PRAGMA) are always allowed. Queries targeting sessions, token_auths, 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
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\TranslatorExceptioninstead 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
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
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
InjectUmamiScript Middleware
Automatically injects the Umami analytics tracking script into HTML responses when
UMAMI_WEBSITE_IDis set.
The script is injected before the closing </head> tag. Set the following environment variables to enable:
| Variable | Description | Default |
|---|---|---|
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 |
Example .env:
UMAMI_WEBSITE_ID=0d38f931-afdc-4a99-a913-5c601fc95629
The injected script:
<script defer src="https://umami.internetguru.io/script.js" data-website-id="0d38f931-afdc-4a99-a913-5c601fc95629"></script>
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
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
Detects the user's timezone via IP geolocation and stores it in the session as
display_timezone.
Uses the GeolocationService to resolve the IP address. Falls back to config('geoip.default_location.timezone') on failure. Resolves only once per session.
VerifyCsrfToken
Extends Laravel's CSRF verification with HMAC-based request signature verification. Requests containing a valid
X-SignatureandX-Timestampheader 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
The
Helpersclass provides useful static methods for Laravel applications.
Configuration and example usage:
-
Add the following lines to
config/app.php:use Illuminate\Support\Facades\Facade; 'aliases' => Facade::defaultAliases()->merge([ 'Helpers' => InternetGuru\LaravelCommon\Support\Helpers::class, ])->toArray(),
-
Use
Helpersclass methods in your application:<meta name="generator" content="{{ Helpers::getAppInfo() }}"/>
Available methods:
| Method | Description |
|---|---|
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 class.
Helper Macros
The package registers a set of useful macros for
Str,Carbon, andNumber. See macros.php for the complete list.
String Macros
| Macro | Description |
|---|---|
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
| Macro | Description |
|---|---|
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
| Macro | Description |
|---|---|
$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 <60 seconds and "1 year" normalization. |
$date->timeForHumans() |
Clean time format (removes leading zeros and :00). |
$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
All Blade components are registered under the ig namespace and can be used with <x-ig::component-name />.
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_choiceif 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).
Usage:
<!-- By default, this will generate breadcrumb items based on the current URL path. --> <x-ig::breadcrumb/> <!-- You can change the divider symbol by setting the divider attribute --> <x-ig::breadcrumb divider="|" /> <!-- If you need to skip certain segments of the URL (e.g., a language prefix), use the skipFirst attribute --> <x-ig::breadcrumb :skipFirst="1" />
Example:
- Assuming you have the following routes defined:
<?php Route::get('/', function () { // ... })->name('home'); Route::get('/products', function () { // ... })->name('products.index'); Route::get('/products/{product}', function ($product) { // ... })->name('products.show');
- And your translation files (
resources/lang/en/navig.php) include:<?php return [ 'home' => 'Long Application Name|LAN', 'products.index' => 'All Products|Products', 'products.show' => 'Product Details', ];
- When you visit the
/products/123URL, the short translation will be used for thehomeandproducts.indexroutes.LAN > Products > Product Details - When you visit the
/productsURL, the short label will be used for thehomeroute.LAN > All Products - When you visit the
/URL, the long label will be used for thehomeroute.Long Application Name
System Messages (Livewire Component)
Renders system temporary success messages and persistent error messages in different colors, with a close button. Powered by Livewire.
The component automatically picks up session success and errors data. You can also send messages dynamically via Livewire events.
Include the component in your Blade template:
<livewire:ig-messages />
Dispatching messages from other Livewire components:
$this->dispatch('ig-message', type: 'success', message: 'Item saved!'); $this->dispatch('ig-message', type: 'danger', message: 'Something went wrong.');
Form Blade Components
The package provides a set of Blade components for forms and various input types.
Notes:
- The Google reCAPTCHA V3 service is enabled by default. To disable it, set the
recaptchaattribute tofalse.
Complete example:
<x-ig::form action="route('test')" :recaptcha="false"> <x-ig::input type="text" name="name" required>Name</x-ig::input> <x-ig::input type="option" name="simple-options" :value="['a', 'b', 'c']">Simple Options</x-ig::input> <x-ig::input type="option" name="advanced-options" :value="[ ['id' => '1', 'value' => 'User 1' ], ['id' => '2', 'value' => 'User 2' ], ['id' => '3', 'value' => 'User 3' ], ]">Advanced Options</x-ig::input> <x-ig::input type="checkbox" name="checkbox" value="1">Checkbox</x-ig::input> <x-ig::input type="radio" name="radio" value="1">Radio</x-ig::input> <x-ig::input type="textarea" name="description">Description</x-ig::input> <x-ig::submit>Submit Form</x-ig::submit> </x-ig::form>
Language Switch Blade Component
Renders a language switcher as a list of links with the current language highlighted.
<x-ig::lang-switch />
Print Button Blade Component
Renders a print button that triggers the browser's print dialog.
<x-ig::print-button />
Footer Copy Blade Component
Renders a copyright footer with provider information and year range.
<x-ig::footer-copy />
Demo Info Blade Component
Renders a demo mode warning banner informing users that displayed information is illustrative and may reset.
<x-ig::demo-info />
Read-Only Mode Info Blade Component
Renders an informational banner indicating the application is in read-only mode and editing is disabled.
<x-ig::read-only-mode-info />
Email Feedback Blade Component
Renders a technical support email link with pre-filled subject and diagnostic data.
<x-ig::email-feedback />
Editable Blade Component
Provides an Alpine.js
editabledata component for inline editing functionality.
<x-ig::editable />
Casts
CarbonIntervalCast
Casts a string to a
CarbonIntervaland back. UsesCarbonInterval::fromString()to parse andforHumans()(in English locale) to serialize.
use Illuminate\Database\Eloquent\Model; use InternetGuru\LaravelCommon\Casts\CarbonIntervalCast; class Task extends Model { protected $casts = [ 'duration' => CarbonIntervalCast::class, ]; }
Traits
Ulid32 Trait
Provides ULID (Crockford Base32) utility methods for Eloquent models. Generates 26-character Base32-encoded UUIDs and adds human-readable formatting, URL generation, and link rendering.
use InternetGuru\LaravelCommon\Traits\Ulid32; class Order extends Model { use Ulid32; }
Available methods:
| Method | Description |
|---|---|
$model->ulidForHumans() |
Formats the ULID with dashes (e.g. 01JM-ABCDEF-GHIJKL-MNOPQR-STUV). |
$model->shortUlidForHumans() |
Returns the last 7 characters of the formatted ULID. |
$model->ulidUrl($usp) |
Generates a URL to the model's show route. |
$model->ulidLink($content) |
Renders an HTML link to the model. |
Model::generateBase32Uuid() |
Generates a new Crockford Base32-encoded UUID (26 characters). |
Rules
Ulid32 Validation Rule
Validates that a value is a valid 26-character Crockford Base32 ULID (no
I,L,O,Ucharacters).
Can be used as a class-based rule or via the globally registered ulid32 rule:
// Class-based use InternetGuru\LaravelCommon\Rules\Ulid32; $request->validate([ 'code' => ['required', new Ulid32], ]); // String-based (registered globally by CommonServiceProvider) $request->validate([ 'code' => 'required|ulid32', ]);
Services
GeolocationService
Resolves an IP address to a geographic location using the
torann/geoippackage. Results are cached and rate-limited (5 lookups per 60 seconds).
use InternetGuru\LaravelCommon\Services\GeolocationService; $geoService = app(GeolocationService::class); $location = $geoService->getLocation('8.8.8.8'); echo $location->timezone; // "America/Chicago" echo $location->country; // "US"
Throws GeolocationServiceException on failure or rate limit.
Notifications
BaseNotification
Abstract queued notification class that captures request context (IP, timezone, user ID, URL) at creation time and sends via the
Features:
- Queued with 10 retries and 2-minute backoff.
- Retry middleware via
LogNotificationFailure— logs warnings on transient failures. - Captures the sender's IP, timezone (via geolocation), authenticated user ID, and current page URL.
- Logs permanently failed notifications.
Extend this class to create your own notifications:
use InternetGuru\LaravelCommon\Notifications\BaseNotification; class OrderConfirmation extends BaseNotification { public function toMail(object $notifiable): MailMessage { return (new \InternetGuru\LaravelCommon\Mail\MailMessage) ->setExtraMailData($this->getExtraMailData()) ->subject('Order Confirmed') ->view(['html' => 'emails.order-confirmed', 'text' => 'emails.order-confirmed-text']); } }
MailMessage
Extends Laravel's
MailMessagewith automatic reference number generation, no-reply detection, and extra mail data injection.
Features:
- Appends a random reference code (
Ref XXXXX) to every subject line for tracking. - Automatically detects no-reply addresses and adds a "replies not delivered" note.
- Supports arbitrary extra data (
setExtraMailData) passed to email views (IP, timezone, user ID, etc.).
Mail Logging
All sent mail notifications are automatically logged to the
mail_logsdatabase table via theLogSentNotificationlistener.
Publish the migration to create the mail_logs table:
php artisan vendor:publish --tag=ig-common:migrations php artisan migrate
Logged fields: to, replyto, subject, body, created_at, updated_at.
Exception Handling
The package registers a custom exception handler that provides user-friendly error pages and JSON responses for common HTTP errors (401, 402, 403, 404, 419, 429, 500, 503).
Features:
- Read-only mode:
DbReadOnlyExceptionreturns a 503 response (JSON or redirect with error). - Connection errors:
ConnectExceptionreturns a friendly error message. - Rate limiting (429) and session expiration (419): Handled with translated messages.
- Debug mode: Uses
dd()for detailed exception inspection. - JSON support: Returns JSON responses when the request expects JSON.
- Redirects to the previously tracked page (via
SetPrevPagemiddleware) on error.
Custom error views are included for standard HTTP status codes. The error pages use the ig-common::layouts.base layout.
Logging
JsonDailyLogger
A custom Monolog logger that writes JSON-formatted daily rotating log files enriched with request context.
Each log entry includes:
- User info: ID, name, email (if authenticated).
- Request input: All inputs except
password,_token, andg-recaptcha-response. Livewire snapshot data is stripped. - Session ID.
- App info: Git branch and commit.
- Request info: URL, IP, HTTP method, server, referrer, user agent.
Configuration in config/logging.php:
'channels' => [ 'json_daily' => [ 'driver' => 'custom', 'via' => InternetGuru\LaravelCommon\Logging\JsonDailyLogger::class, 'path' => storage_path('logs/app.log'), 'days' => 14, 'level' => 'debug', ], ],
Localization
The package includes translations in English (en), Czech (cs), and Danish (da) for:
- Error pages (
errors.php) – HTTP status messages and descriptions. - Layout strings (
layouts.php) – Footer, email templates, support links, and UI labels. - System messages (
messages.php) – Validation messages, email labels, and demo mode warnings. - Navigation (
navig.php) – Breadcrumb labels for routes.
Publishing Assets
You can publish package assets to customize them:
# Publish database migrations php artisan vendor:publish --tag=ig-common:migrations # Publish configuration php artisan vendor:publish --tag=ig-common:config # Publish views for customization php artisan vendor:publish --tag=ig-common:views # Publish language files php artisan vendor:publish --tag=ig-common:lang
License & Commercial Terms
License
Copyright © 2026 Internet Guru
This software is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) license.
Disclaimer: This software is provided "as is", without warranty of any kind, express or implied. In no event shall the authors or copyright holders be liable for any claim, damages or other liability.
Commercial Use
The standard CC BY-NC-SA license prohibits commercial use. If you wish to use this software in a commercial environment or product, we offer flexible commercial licenses tailored to:
- Your company size.
- The nature of your project.
- Your specific integration needs.
Note: In many instances (especially for startups or small-scale tools), this may result in no fees being charged at all. Please contact us to obtain written permission or a commercial agreement.
Contact for Licensing: info@internetguru.io
Professional Services
Are you looking to get the most out of this project? We are available for:
- Custom Development: Tailoring the software to your specific requirements.
- Integration & Support: Helping your team implement and maintain the solution.
- Training & Workshops: Seminars and hands-on workshops for your developers.
Reach out to us at info@internetguru.io — we are more than happy to assist you!