PHPackages                             bywyd/laravel-qol - 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. bywyd/laravel-qol

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

bywyd/laravel-qol
=================

Quality of Life enhancements for Laravel - supportive tools, traits, and utilities

v1.1.3(3mo ago)09MITPHPPHP ^8.1|^8.2|^8.3

Since Dec 9Pushed 3mo agoCompare

[ Source](https://github.com/bywyd/laravel-qol)[ Packagist](https://packagist.org/packages/bywyd/laravel-qol)[ RSS](/packages/bywyd-laravel-qol/feed)WikiDiscussions main Synced 1mo ago

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

Laravel QoL
===========

[](#laravel-qol)

**Laravel Quality of Life** - A collection of helpful traits, utilities, and tools to enhance your Laravel development experience.

Features
--------

[](#features)

### Media Management

[](#media-management)

- **HasImages Trait** - Easy image management with ordering and tagging
- **HasFiles Trait** - Generic file upload and management
- **HasVideos Trait** - Video upload with metadata support
- **PhotoImage Model** - Complete image model with helper methods
- **File Model** - Flexible file handling with type detection
- **Video Model** - Video model with duration, resolution, and thumbnails

### Model Enhancements

[](#model-enhancements)

- **HasHistory Trait** - Automatic model change tracking
- **HasRoles Trait** - Complete role and permission system for users
- **HasIntegrations Trait** - Manage user integrations with OAuth, API keys, and credentials
- **HasSettings Trait** - Universal settings system (app-wide, per-user, per-model)
- **HasUuid Trait** - Automatic UUID generation for models
- **HasSlug Trait** - Automatic slug generation from any field
- **HasStatus Trait** - Status management with active/inactive scopes
- **Sortable Trait** - Easy ordering/sorting functionality
- **Cacheable Trait** - Built-in model-level caching
- **Searchable Trait** - Simple and full-text search capabilities

### Authorization

[](#authorization)

- **Role Model** - Hierarchical role system with levels
- **Permission Model** - Granular permission control
- **Middleware** - Route protection with role, permission, or both
- **Blade Directives** - Template-level authorization checks
- **Gates Integration** - Automatic Laravel Gate registration

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

[](#installation)

Install via Composer:

```
composer require bywyd/laravel-qol
```

Configuration
-------------

[](#configuration)

Publish the configuration file (optional):

```
php artisan vendor:publish --tag=laravel-qol-config
```

Publish the migrations:

```
php artisan vendor:publish --tag=laravel-qol-migrations
php artisan migrate
```

Usage
-----

[](#usage)

### HasHistory Trait

[](#hashistory-trait)

Track all changes made to your models automatically:

```
use Bywyd\LaravelQol\Traits\HasHistory;

class Post extends Model
{
    use HasHistory;

    // Optional: Exclude specific attributes from history
    protected $historyExcludedAttributes = ['views', 'updated_at'];

    // Optional: Only log specific events
    protected $historyEvents = ['created', 'updated'];

    // Optional: Keep histories when model is deleted
    protected $deleteHistoriesOnDelete = false;
}

// Usage
$post = Post::find(1);
$post->histories; // Get all history records
$post->latestHistory; // Get the latest history

// Manual history logging
$post->logHistory(HistoryLogTypes::CUSTOM, 'Custom action performed');

// Temporarily disable history logging
$post->withoutHistory(function($post) {
    $post->update(['title' => 'No history logged']);
});
```

### HasImages Trait

[](#hasimages-trait)

Manage images for your models with ease:

```
use Bywyd\LaravelQol\Traits\HasImages;

class Product extends Model
{
    use HasImages;
}

// Usage
$product = Product::find(1);

// Upload an image
$image = $product->uploadImage($request->file('image'), 0, 'gallery');

// Get all images
$product->images;

// Get images by tag
$product->imagesByTag('gallery');

// Get primary image
$product->primaryImage();

// Reorder images
$product->reorderImages([3, 1, 2]); // Array of image IDs

// Delete an image
$product->deleteImage($image);

// Delete all images
$product->deleteAllImages();
```

### HasFiles Trait

[](#hasfiles-trait)

Upload and manage any type of file:

```
use Bywyd\LaravelQol\Traits\HasFiles;

class Document extends Model
{
    use HasFiles;
}

// Usage
$document = Document::find(1);

// Upload a file
$file = $document->uploadFile($request->file('attachment'), 0, 'contract', [
    'department' => 'Legal'
]);

// Get all files
$document->files;

// Get files by tag
$document->filesByTag('contract');

// Get document files (PDFs, DOCs, etc.)
$document->documents();

// Download a file
return $file->download();

// Delete a file
$document->deleteFile($file);
```

### HasVideos Trait

[](#hasvideos-trait)

Manage video uploads with metadata:

```
use Bywyd\LaravelQol\Traits\HasVideos;

class Course extends Model
{
    use HasVideos;
}

// Usage
$course = Course::find(1);

// Upload a video
$video = $course->uploadVideo($request->file('video'), 0, 'lesson-1');

// Access video properties
$video->url; // Public URL
$video->human_size; // "50.5 MB"
$video->human_duration; // "5:23"
$video->aspect_ratio; // "16:9"

// Quality checks
$video->isHD(); // 720p or higher
$video->isFullHD(); // 1080p or higher
$video->is4K(); // 2160p or higher

// Get HD videos
$course->hdVideos();

// Delete a video
$course->deleteVideo($video);
```

### HasUuid Trait

[](#hasuuid-trait)

Automatically generate UUIDs for your models:

```
use Bywyd\LaravelQol\Traits\HasUuid;

class User extends Model
{
    use HasUuid;

    // Optional: Customize UUID column
    protected $uuidColumn = 'uuid';
}

// Usage
$user = User::create(['name' => 'John']);
$user->uuid; // "550e8400-e29b-41d4-a716-446655440000"

// Find by UUID
$user = User::findByUuid('550e8400-e29b-41d4-a716-446655440000');
$user = User::findByUuidOrFail($uuid);
```

### HasSlug Trait

[](#hasslug-trait)

Automatic slug generation from any field:

```
use Bywyd\LaravelQol\Traits\HasSlug;

class Article extends Model
{
    use HasSlug;

    // Optional: Customize slug source
    protected $slugSource = 'title';

    // Optional: Customize slug column
    protected $slugColumn = 'slug';

    // Optional: Prevent regeneration on update
    protected $regenerateSlugOnUpdate = false;
}

// Usage
$article = Article::create(['title' => 'Hello World']);
$article->slug; // "hello-world"

// Find by slug
$article = Article::findBySlug('hello-world');
$article = Article::findBySlugOrFail('hello-world');
```

### HasStatus Trait

[](#hasstatus-trait)

Manage model status with convenient methods:

```
use Bywyd\LaravelQol\Traits\HasStatus;

class Task extends Model
{
    use HasStatus;

    // Optional: Customize status column
    protected $statusColumn = 'status';

    // Optional: Customize status values
    protected $activeStatusValue = 1;
    protected $inactiveStatusValue = 0;
}

// Usage
$task = Task::find(1);

// Status checks
$task->isActive();
$task->isInactive();

// Status changes
$task->activate();
$task->deactivate();
$task->toggleStatus();

// Query scopes
Task::active()->get();
Task::inactive()->get();
Task::status(1)->get();
```

### Sortable Trait

[](#sortable-trait)

Add ordering functionality to your models:

```
use Bywyd\LaravelQol\Traits\Sortable;

class MenuItem extends Model
{
    use Sortable;

    // Optional: Customize sort column
    protected $sortColumn = 'order';
}

// Usage
$item = MenuItem::find(1);

// Move operations
$item->moveUp();
$item->moveDown();
$item->moveTo(5);
$item->swapWith($otherItem);

// Query scope
MenuItem::ordered()->get(); // Ordered by sort column
MenuItem::ordered('desc')->get();
```

### Cacheable Trait

[](#cacheable-trait)

Built-in model caching:

```
use Bywyd\LaravelQol\Traits\Cacheable;

class Settings extends Model
{
    use Cacheable;

    // Optional: Customize cache prefix
    protected $cachePrefix = 'settings';

    // Optional: Customize TTL (seconds)
    protected $cacheTtl = 3600;
}

// Usage
$settings = Settings::find(1);

// Cache data
$value = $settings->remember('config', function() {
    return expensive_operation();
});

// Cache forever
$value = $settings->rememberForever('permanent', function() {
    return static_data();
});

// Clear cache
$settings->clearCache();
```

### Searchable Trait

[](#searchable-trait)

Add search functionality:

```
use Bywyd\LaravelQol\Traits\Searchable;

class Product extends Model
{
    use Searchable;

    // Define searchable columns
    protected $searchable = ['name', 'description', 'category.name'];
}

// Usage
// Simple search
Product::search('laptop')->get();

// Custom columns
Product::search('laptop', ['name', 'sku'])->get();

// Full-text search (MySQL)
Product::fullTextSearch('gaming laptop')->get();
```

### HasRoles Trait

[](#hasroles-trait)

Complete role and permission system for User models:

```
use Bywyd\LaravelQol\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;
}

// Assign roles
$user->assignRole('admin');
$user->assignRole(['editor', 'moderator']);

// Remove roles
$user->removeRole('editor');

// Sync roles (removes all existing roles and assigns new ones)
$user->syncRoles(['admin', 'super-admin']);

// Check roles
$user->hasRole('admin'); // true
$user->hasAnyRole(['admin', 'editor']); // true if user has any
$user->hasAllRoles(['admin', 'editor']); // true if user has all

// Give direct permissions
$user->givePermission('edit-posts');
$user->givePermission(['edit-posts', 'delete-posts']);

// Revoke permissions
$user->revokePermission('delete-posts');

// Sync permissions
$user->syncPermissions(['edit-posts', 'view-posts']);

// Check permissions
$user->hasPermission('edit-posts'); // true
$user->hasAnyPermission(['edit-posts', 'delete-posts']); // true if has any
$user->hasAllPermissions(['edit-posts', 'view-posts']); // true if has all

// Get all permissions (direct + from roles)
$user->getAllPermissions();

// Check super admin
$user->isSuperAdmin(); // true if has super-admin role or * permission

// Query scopes
User::role('admin')->get();
User::role(['admin', 'editor'])->get();
User::permission('edit-posts')->get();
User::permission(['edit-posts', 'delete-posts'])->get();
```

### Role Model

[](#role-model)

Manage roles with hierarchical levels:

```
use Bywyd\LaravelQol\Models\Role;

// Create a role
$role = Role::create([
    'name' => 'Administrator',
    'slug' => 'admin',
    'description' => 'Full access to the system',
    'level' => 100, // Higher = more privileges
    'is_default' => false,
]);

// Assign permissions to role
$role->givePermission('edit-posts');
$role->givePermission(['delete-posts', 'manage-users']);

// Revoke permissions
$role->revokePermission('delete-posts');

// Sync permissions
$role->syncPermissions(['edit-posts', 'view-posts']);

// Check if role has permission
$role->hasPermission('edit-posts'); // true

// Check if super admin
$role->isSuperAdmin(); // true if has * permission

// Get users with this role
$role->users;

// Query scopes
Role::default()->first(); // Get default role
Role::byLevel()->get(); // Order by level
Role::byLevel('desc')->get();
```

### Permission Model

[](#permission-model)

Create and manage permissions:

```
use Bywyd\LaravelQol\Models\Permission;

// Create a permission
$permission = Permission::create([
    'name' => 'Edit Posts',
    'slug' => 'edit-posts',
    'description' => 'Can create and edit posts',
    'group' => 'posts', // Group related permissions
]);

// Get permissions by group
Permission::byGroup('posts')->get();

// Get all permissions grouped
$grouped = Permission::getAllGrouped();
// Returns: ['posts' => [...], 'users' => [...]]

// Wildcard permission (grants all permissions)
Permission::create([
    'name' => 'All Permissions',
    'slug' => '*',
    'description' => 'Super admin permission',
]);
```

### Route Protection with Middleware

[](#route-protection-with-middleware)

Protect routes using middleware:

```
// In your routes file
Route::middleware(['role:admin'])->group(function () {
    Route::get('/admin/dashboard', [AdminController::class, 'index']);
});

// Multiple roles (OR condition)
Route::middleware(['role:admin|editor'])->group(function () {
    Route::get('/posts/create', [PostController::class, 'create']);
});

// Permission middleware
Route::middleware(['permission:edit-posts'])->group(function () {
    Route::put('/posts/{post}', [PostController::class, 'update']);
});

// Multiple permissions (OR condition)
Route::middleware(['permission:edit-posts|delete-posts'])->group(function () {
    Route::get('/posts/manage', [PostController::class, 'manage']);
});

// Role OR Permission (if user has either)
Route::middleware(['role_or_permission:admin|edit-posts'])->group(function () {
    Route::post('/posts', [PostController::class, 'store']);
});
```

### Blade Directives

[](#blade-directives)

Use in your Blade templates:

```
{{-- Check single role --}}
@role('admin')
    Admin Panel
@endrole

{{-- Alternative syntax --}}
@hasrole('admin')
    You are an admin
@endhasrole

{{-- Check any role --}}
@hasanyrole(['admin', 'editor'])
    Edit Content
@endhasanyrole

{{-- Check all roles --}}
@hasallroles(['admin', 'super-admin'])
    Critical Action
@endhasallroles

{{-- Check permission --}}
@permission('edit-posts')
    Create Post
@endpermission

{{-- Alternative syntax --}}
@haspermission('delete-posts')
    Delete
@endhaspermission

{{-- Check any permission --}}
@hasanypermission(['edit-posts', 'delete-posts'])
    Post Management
@endhasanypermission

{{-- Check all permissions --}}
@hasallpermissions(['edit-posts', 'publish-posts'])
    Publish
@endhasallpermissions

{{-- Using @else --}}
@role('admin')
    Admin content
@else
    Regular user content
@endrole
```

### Laravel Gates

[](#laravel-gates)

Permissions are automatically registered as Gates:

```
// In your controller or anywhere
if (Gate::allows('edit-posts')) {
    // User can edit posts
}

if (Gate::denies('delete-posts')) {
    // User cannot delete posts
}

// Using authorize
$this->authorize('edit-posts');

// In routes
Route::get('/posts/{post}/edit', [PostController::class, 'edit'])
    ->can('edit-posts');
```

### Policy Integration

[](#policy-integration)

Use with Laravel Policies:

```
// In your Policy
public function update(User $user, Post $post)
{
    return $user->hasPermission('edit-posts') || $user->id === $post->user_id;
}

public function delete(User $user, Post $post)
{
    return $user->hasPermission('delete-posts') ||
           $user->hasRole('admin');
}
```

### Creating a Complete Authorization System

[](#creating-a-complete-authorization-system)

```
// 1. Create permissions
$permissions = [
    ['name' => 'View Posts', 'slug' => 'view-posts', 'group' => 'posts'],
    ['name' => 'Create Posts', 'slug' => 'create-posts', 'group' => 'posts'],
    ['name' => 'Edit Posts', 'slug' => 'edit-posts', 'group' => 'posts'],
    ['name' => 'Delete Posts', 'slug' => 'delete-posts', 'group' => 'posts'],
    ['name' => 'Manage Users', 'slug' => 'manage-users', 'group' => 'users'],
];

foreach ($permissions as $permission) {
    Permission::create($permission);
}

// 2. Create roles
$superAdmin = Role::create([
    'name' => 'Super Admin',
    'slug' => 'super-admin',
    'level' => 100,
]);
$superAdmin->givePermission('*'); // All permissions

$admin = Role::create([
    'name' => 'Admin',
    'slug' => 'admin',
    'level' => 50,
]);
$admin->givePermission(['view-posts', 'create-posts', 'edit-posts', 'manage-users']);

$editor = Role::create([
    'name' => 'Editor',
    'slug' => 'editor',
    'level' => 25,
]);
$editor->givePermission(['view-posts', 'create-posts', 'edit-posts']);

$user = Role::create([
    'name' => 'User',
    'slug' => 'user',
    'level' => 1,
    'is_default' => true,
]);
$user->givePermission('view-posts');

// 3. Assign to users
$user = User::find(1);
$user->assignRole('super-admin');
```

### HasIntegrations Trait

[](#hasintegrations-trait)

Manage user integrations with third-party services:

```
use Bywyd\LaravelQol\Traits\HasIntegrations;

class User extends Authenticatable
{
    use HasIntegrations;
}

// Create OAuth integration (e.g., Google, GitHub, Facebook)
$user->createOAuthIntegration('google', [
    'provider_id' => '123456789',
    'provider_name' => 'Google',
    'access_token' => 'ya29.a0AfH6SMC...',
    'refresh_token' => '1//0gOZp...',
    'expires_in' => 3600, // seconds
    'metadata' => [
        'email' => 'user@gmail.com',
        'name' => 'John Doe',
        'avatar' => 'https://...',
    ],
]);

// Create API Key integration (e.g., Stripe, AWS, SendGrid)
$user->createApiKeyIntegration('stripe', [
    'provider_name' => 'Stripe',
    'api_key' => 'sk_test_51H...',
    'api_secret' => 'whsec_...',
    'metadata' => [
        'account_id' => 'acct_123',
        'mode' => 'test',
    ],
]);

// Create custom integration
$user->createIntegration('webhook', 'webhook', [
    'provider_name' => 'My Webhook Service',
    'credentials' => [
        'url' => 'https://api.example.com/webhook',
        'secret' => 'webhook_secret_123',
    ],
]);

// Check if user has integration
if ($user->hasIntegration('google')) {
    // User has Google integration
}

// Check if integration is active
if ($user->hasActiveIntegration('stripe')) {
    // Stripe integration is active
}

// Get integration
$integration = $user->getIntegration('google');

// Access decrypted credentials
$accessToken = $user->getIntegrationAccessToken('google');
$apiKey = $user->getIntegrationApiKey('stripe');
$apiSecret = $user->getIntegrationApiSecret('stripe');

// Check token validity
$integration = $user->getIntegration('google');
if ($integration->hasValidToken()) {
    // Token exists and not expired
}

// Activate/Deactivate integration
$user->activateIntegration('google');
$user->deactivateIntegration('stripe');

// Remove integration
$user->removeIntegration('github');

// Update metadata
$user->updateIntegrationMetadata('google', [
    'last_sync' => now(),
    'sync_count' => 5,
]);

// Mark as used (updates last_used_at)
$user->markIntegrationAsUsed('stripe');

// Get all integrations
$user->integrations; // All integrations
$user->activeIntegrations; // Only active

// Filter by type
$user->oauthIntegrations(); // OAuth only
$user->apiKeyIntegrations(); // API keys only
$user->validIntegrations(); // Valid tokens only

// Query scopes
UserIntegration::provider('google')->get();
UserIntegration::type('oauth')->get();
UserIntegration::active()->get();
UserIntegration::validToken()->get();
```

### UserIntegration Model

[](#userintegration-model)

Direct model usage:

```
use Bywyd\LaravelQol\Models\UserIntegration;

$integration = UserIntegration::find(1);

// Encrypted credential methods
$integration->setAccessToken('new_token');
$integration->setRefreshToken('new_refresh');
$integration->setApiKey('sk_test_123');
$integration->setApiSecret('secret_456');

$integration->save();

// Decrypted access
$token = $integration->getDecryptedAccessToken();
$refresh = $integration->getDecryptedRefreshToken();
$apiKey = $integration->getDecryptedApiKey();
$apiSecret = $integration->getDecryptedApiSecret();

// Status checks
$integration->isTokenExpired(); // Check if token expired
$integration->hasValidToken(); // Token exists and not expired

// Actions
$integration->activate();
$integration->deactivate();
$integration->markAsUsed();

// Relationships
$integration->user; // Get the user
```

### Common Integration Examples

[](#common-integration-examples)

```
// Google OAuth
$user->createOAuthIntegration('google', [
    'provider_id' => $googleUser->id,
    'provider_name' => 'Google',
    'access_token' => $googleUser->token,
    'refresh_token' => $googleUser->refreshToken,
    'expires_in' => $googleUser->expiresIn,
    'metadata' => [
        'email' => $googleUser->email,
        'name' => $googleUser->name,
    ],
]);

// GitHub OAuth
$user->createOAuthIntegration('github', [
    'provider_id' => $githubUser->id,
    'provider_name' => 'GitHub',
    'access_token' => $githubUser->token,
    'metadata' => [
        'username' => $githubUser->nickname,
        'repos_url' => $githubUser->user['repos_url'],
    ],
]);

// Stripe
$user->createApiKeyIntegration('stripe', [
    'provider_name' => 'Stripe',
    'api_key' => config('services.stripe.secret'),
    'metadata' => [
        'customer_id' => $stripeCustomer->id,
        'mode' => 'live',
    ],
]);

// AWS
$user->createApiKeyIntegration('aws', [
    'provider_name' => 'AWS',
    'api_key' => $credentials['access_key_id'],
    'api_secret' => $credentials['secret_access_key'],
    'credentials' => [
        'region' => 'us-east-1',
        'bucket' => 'my-bucket',
    ],
]);

// SendGrid
$user->createApiKeyIntegration('sendgrid', [
    'provider_name' => 'SendGrid',
    'api_key' => $sendgridApiKey,
    'metadata' => [
        'from_email' => 'noreply@example.com',
        'from_name' => 'My App',
    ],
]);

// Slack Webhook
$user->createIntegration('slack', 'webhook', [
    'provider_name' => 'Slack',
    'credentials' => [
        'webhook_url' => 'https://hooks.slack.com/services/...',
        'channel' => '#general',
    ],
]);
```

### Security Features

[](#security-features)

All sensitive data is automatically encrypted:

- Access tokens
- Refresh tokens
- API keys
- API secrets
- Custom credentials

The trait uses Laravel's built-in encryption, ensuring data is secure at rest.

Middleware
----------

[](#middleware)

The package includes 10 production-ready middleware:

### SetLocale Middleware

[](#setlocale-middleware)

Automatically sets application locale based on multiple sources (priority order):

```
// In your routes or middleware group
Route::middleware('locale')->group(function () {
    // Your routes
});

// Supports:
// 1. Query parameter: ?locale=es
// 2. Session: session('locale')
// 3. User preference: $user->getPreferredLocale()
// 4. Cookie: locale=fr
// 5. Accept-Language header
```

### RestrictAccess Middleware

[](#restrictaccess-middleware)

Maintenance mode with granular access control:

```
// Enable in .env
ACCESS_RESTRICTION_ENABLED=true
ALLOWED_IPS="192.168.1.1,10.0.0.0/24,172.16.*.*"
BYPASS_TOKEN=secret-token-123

// Apply to routes
Route::middleware('restrict.access')->group(function () {
    // Protected routes
});

// Access with bypass token
// ?bypass_token=secret-token-123
// Header: X-Bypass-Token: secret-token-123
```

### ForceJsonResponse Middleware

[](#forcejsonresponse-middleware)

Force JSON responses for API applications:

```
Route::middleware('force.json')->group(function () {
    // All responses will be JSON
});
```

### LogRequestResponse Middleware

[](#logrequestresponse-middleware)

Log all HTTP requests and responses:

```
Route::middleware('log.request')->group(function () {
    // Requests/responses logged
});

// Configure in config/laravel-qol.php
'logging' => [
    'log_requests' => true,
    'log_responses' => true,
    'log_request_body' => false,
    'log_response_body' => false,
    'sensitive_keys' => ['password', 'token'],
],
```

### SecurityHeaders Middleware

[](#securityheaders-middleware)

Add security headers automatically:

```
Route::middleware('security.headers')->group(function () {
    // Security headers added
});

// Adds: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection,
// HSTS, CSP, Referrer-Policy, Permissions-Policy
```

### RateLimitByUser Middleware

[](#ratelimitbyuser-middleware)

Rate limiting per user or IP:

```
// 60 requests per minute
Route::middleware('rate.limit.user:60,1')->group(function () {
    //
});

// 100 requests per 5 minutes
Route::middleware('rate.limit.user:100,5')->group(function () {
    //
});
```

### ConvertEmptyStringsToNull Middleware

[](#convertemptystringstonull-middleware)

Convert empty strings to null in requests:

```
Route::middleware('convert.empty.strings')->group(function () {
    // '' becomes null
});
```

### TrimStrings Middleware

[](#trimstrings-middleware)

Automatically trim string inputs:

```
Route::middleware('trim.strings')->group(function () {
    // All strings trimmed (except passwords)
});
```

### ApiVersioning Middleware

[](#apiversioning-middleware)

API versioning support:

```
// Require specific version
Route::middleware('api.version:v1')->group(function () {
    //
});

// Accept any supported version
Route::middleware('api.version')->group(function () {
    $version = request()->attributes->get('api_version');
});

// Version sources:
// - Header: Accept: application/vnd.api.v1+json
// - Header: X-API-Version: v1
// - Query: ?version=v1
// - URL: /api/v1/users
```

### CorsMiddleware

[](#corsmiddleware)

Advanced CORS handling:

```
Route::middleware('cors')->group(function () {
    //
});

// Configure in config/laravel-qol.php
'cors' => [
    'allowed_origins' => ['*'],
    'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE'],
    'allowed_headers' => ['Content-Type', 'Authorization'],
    'allow_credentials' => false,
],
```

Universal Settings System
-------------------------

[](#universal-settings-system)

Flexible settings system supporting app-wide, per-user, and per-model settings.

### App-Wide Settings

[](#app-wide-settings)

Use the `Settings` facade for application-level settings:

```
use Bywyd\LaravelQol\Facades\Settings;

// Set settings
Settings::set('site_name', 'My Application');
Settings::set('items_per_page', 25);
Settings::set('maintenance_mode', false);
Settings::set('features', ['api', 'webhooks', 'exports']);

// Organize by groups
Settings::set('smtp_host', 'smtp.gmail.com', 'email');
Settings::set('smtp_port', 587, 'email');
Settings::set('theme_color', '#FF5733', 'appearance');

// Get settings
$siteName = Settings::get('site_name');
$perPage = Settings::get('items_per_page', 10); // with default

// Get all settings in a group
$emailSettings = Settings::getGroup('email');
// ['smtp_host' => 'smtp.gmail.com', 'smtp_port' => 587]

// Check if exists
if (Settings::has('api_key')) {
    //
}

// Remove setting
Settings::remove('old_setting');

// Set multiple at once
Settings::setMultiple([
    'key1' => 'value1',
    'key2' => 'value2',
], 'group_name');

// Increment/Decrement numeric values
Settings::increment('page_views');
Settings::decrement('credits', 5);

// Toggle boolean values
Settings::toggle('feature_enabled');

// Store with metadata
Settings::set('api_key', 'secret', 'api', true, [
    'description' => 'Third-party API key',
    'editable' => false,
]);
```

### Per-User Settings

[](#per-user-settings)

Add the `HasSettings` trait to your User model:

```
use Bywyd\LaravelQol\Traits\HasSettings;

class User extends Authenticatable
{
    use HasSettings;
}

// Set user preferences
$user->setSetting('theme', 'dark');
$user->setSetting('language', 'es');
$user->setSetting('notifications_enabled', true);
$user->setSetting('email_frequency', 'daily', 'notifications');

// Get user settings
$theme = $user->getSetting('theme', 'light'); // with default
$language = $user->getSetting('language');

// Organize by groups
$user->setSetting('push_enabled', true, 'notifications');
$user->setSetting('email_enabled', false, 'notifications');
$notificationSettings = $user->getSettingsGroup('notifications');

// Get all user settings
$allSettings = $user->getAllSettings();
// ['general.theme' => 'dark', 'general.language' => 'es', ...]

// Public settings (visible to others)
$user->setSetting('profile_visibility', 'public', 'privacy', true);
$publicSettings = $user->getAllSettings(true); // only public

// Batch operations
$user->setSettings([
    'theme' => 'dark',
    'font_size' => 'medium',
    'compact_mode' => true,
], 'appearance');

// Clear settings
$user->clearSettings(); // all
$user->clearSettings('notifications'); // specific group

// Numeric operations
$user->incrementSetting('posts_count');
$user->decrementSetting('credits', 10);

// Boolean operations
$user->toggleSetting('notifications_enabled');
```

### Per-Model Settings

[](#per-model-settings)

Add the `HasSettings` trait to any model:

```
use Bywyd\LaravelQol\Traits\HasSettings;

class Post extends Model
{
    use HasSettings;
}

$post = Post::find(1);

// Model-specific settings
$post->setSetting('featured', true);
$post->setSetting('visibility', 'public');
$post->setSetting('allow_comments', true);
$post->setSetting('views_count', 0, 'analytics');

// Get settings
$featured = $post->getSetting('featured', false);
$visibility = $post->getSetting('visibility');

// Analytics example
$post->incrementSetting('views_count', 1, 'analytics');
$post->setSetting('last_viewed_at', now(), 'analytics');

$analytics = $post->getSettingsGroup('analytics');
// ['views_count' => 150, 'last_viewed_at' => '2024-01-01 12:00:00']
```

### Settings Features

[](#settings-features)

**Type Support:**

- String
- Integer
- Float
- Boolean
- Array
- JSON

**Automatic Caching:**

- Settings are cached automatically
- Cache cleared on update/delete
- Configurable TTL

**Organization:**

- Group settings logically
- Isolate by model instance
- Public vs private settings

**Metadata:**

- Store additional info about settings
- Descriptions, editability flags, etc.

### Real-World Examples

[](#real-world-examples)

```
// E-commerce: Product settings
$product->setSetting('on_sale', true);
$product->setSetting('discount_percentage', 20);
$product->setSetting('stock_alert_threshold', 5, 'inventory');

// Blog: Post settings
$post->setSetting('featured', true);
$post->setSetting('allow_comments', false);
$post->setSetting('publish_at', '2024-12-25 00:00:00', 'scheduling');

// SaaS: Organization settings
$organization->setSetting('max_users', 50, 'limits');
$organization->setSetting('api_enabled', true, 'features');
$organization->setSetting('webhook_url', 'https://...', 'integrations');

// Multi-tenant: Tenant customization
$tenant->setSetting('primary_color', '#FF5733', 'branding');
$tenant->setSetting('logo_url', 'https://...', 'branding');
$tenant->setSetting('custom_domain', 'tenant.example.com', 'domain');

// User preferences dashboard
$preferences = $user->getSettingsGroup('preferences');
foreach ($preferences as $key => $value) {
    echo "{$key}: {$value}";
}
```

### CommonScopes Trait

[](#commonscopes-trait)

Add powerful query scopes to your models:

```
use Bywyd\LaravelQol\Traits\CommonScopes;

class Product extends Model
{
    use CommonScopes;
}

// Usage examples:
Product::active()->get();
Product::recent(7)->get(); // Last 7 days
Product::thisMonth()->get();
Product::popular('views_count', 100)->get();
Product::published()->get();
Product::whereLike('search term', ['name', 'description'])->get();
Product::smartPaginate(20); // Auto-handles per_page from request
```

Available scopes: `active()`, `inactive()`, `recent()`, `older()`, `today()`, `thisWeek()`, `thisMonth()`, `thisYear()`, `betweenDates()`, `latest()`, `oldest()`, `whereIds()`, `whereNotIds()`, `whereLike()`, `whereEmpty()`, `whereNotEmpty()`, `random()`, `popular()`, `featured()`, `published()`, `draft()`, `smartPaginate()`

### ApiResponse Trait

[](#apiresponse-trait)

Standardized API responses for controllers:

```
use Bywyd\LaravelQol\Traits\ApiResponse;

class UserController extends Controller
{
    use ApiResponse;

    public function index()
    {
        $users = User::paginate();
        return $this->paginated($users, 'Users retrieved successfully');
    }

    public function store(Request $request)
    {
        $user = User::create($request->validated());
        return $this->created($user, 'User created successfully');
    }

    public function show(User $user)
    {
        return $this->success($user);
    }

    public function update(Request $request, User $user)
    {
        $user->update($request->validated());
        return $this->updated($user);
    }

    public function destroy(User $user)
    {
        $user->delete();
        return $this->deleted();
    }
}
```

Available methods: `success()`, `error()`, `created()`, `updated()`, `deleted()`, `notFound()`, `unauthorized()`, `forbidden()`, `validationError()`, `serverError()`, `paginated()`, `noContent()`

### Request Macros

[](#request-macros)

Enhanced request handling:

```
// Check if any of the keys exist
if (request()->hasAny(['email', 'username'])) {
    // ...
}

// Check if all keys exist
if (request()->hasAll(['name', 'email', 'password'])) {
    // ...
}

// Get boolean value (handles 'true', '1', 'yes', 'on')
$active = request()->boolean('is_active', false);

// Get array of IDs from comma-separated or array
$ids = request()->ids('user_ids'); // "1,2,3" or [1,2,3] => [1,2,3]

// Get sanitized search term
$search = request()->search('q');

// Get real IP (considering proxies, Cloudflare, etc.)
$ip = request()->realIp();

// Check if mobile device
if (request()->isMobile()) {
    // ...
}

// Get sort parameters
$sort = request()->sort('created_at', 'desc');
// Returns: ['column' => 'created_at', 'direction' => 'desc']

// Get filters (removes empty values)
$filters = request()->filters(['status', 'category', 'price_min']);
```

### Collection Macros

[](#collection-macros)

Extended collection functionality:

```
// Recursively convert to array
$data = collect($nested)->recursive()->toArray();

// Group by multiple keys
$grouped = $users->groupByMultiple(['country', 'city']);

// Export to CSV
$csv = $users->toCsv(['ID', 'Name', 'Email']);

// Check for duplicates
if ($items->hasDuplicates('email')) {
    // ...
}

// Transpose (rows to columns)
$transposed = collect([[1, 2], [3, 4]])->transpose();
// Result: [[1, 3], [2, 4]]

// Get statistics
$stats = $numbers->stats();
// Returns: ['count', 'sum', 'avg', 'min', 'max', 'median']

// Filter null/empty values
$filtered = $collection->filterNull()->filterEmpty();

// Manual pagination
$paginated = $collection->paginate(15);
```

### Validation Rules

[](#validation-rules)

Custom validation rules:

```
use Bywyd\LaravelQol\Rules\PhoneNumber;
use Bywyd\LaravelQol\Rules\StrongPassword;
use Bywyd\LaravelQol\Rules\Username;

// Phone number validation
'phone' => ['required', new PhoneNumber()],

// Strong password validation
'password' => [
    'required',
    new StrongPassword(
        minLength: 8,
        requireUppercase: true,
        requireLowercase: true,
        requireNumbers: true,
        requireSpecialChars: true
    )
],

// Username validation
'username' => [
    'required',
    new Username(
        minLength: 3,
        maxLength: 20,
        allowDash: true,
        allowUnderscore: true,
        allowDot: false
    )
],
```

### Helper Functions

[](#helper-functions)

Global utility functions:

```
// Limit words in string
$excerpt = str_limit_words($text, 10);

// Simple money formatting
$price = money_format_simple(1234.56, '$', 2); // "$1,234.56"

// Calculate percentage
$percent = percentage(25, 100); // 25.00

// Filter array recursively
$filtered = array_filter_recursive($array);

// Sanitize filename
$safe = sanitize_filename('My File (1).pdf'); // "My_File_1.pdf"

// Generate random string
$token = generate_random_string(32); // Alphanumeric
$password = generate_random_string(16, false); // With special chars

// Convert bytes to human readable
$size = bytes_to_human(1048576); // "1.00 MB"

// Convert human readable to bytes
$bytes = human_to_bytes('10MB'); // 10485760

// Check if string is valid JSON
if (is_json($string)) {
    // ...
}

// Safe Carbon parsing
$date = carbon_parse_safe($input, now());

// Active route helper (for navigation)
Users

// Get client browser
$browser = get_client_browser(); // "Chrome", "Firefox", etc.

// Truncate middle of string
$truncated = truncate_middle('very-long-filename.txt', 20); // "very-long...ame.txt"
```

### Database Utilities

[](#database-utilities)

#### QueryLogger

[](#querylogger)

Log and analyze database queries:

```
use Bywyd\LaravelQol\Utilities\QueryLogger;

// Enable query logging
QueryLogger::enable();

// Your code here...
User::all();
Post::with('comments')->get();

// Get all queries
$queries = QueryLogger::getQueries();

// Get total execution time
$time = QueryLogger::getTotalTime(); // in milliseconds

// Get query count
$count = QueryLogger::getCount();

// Get slowest queries
$slow = QueryLogger::getSlowestQueries(10);

// Log to file
QueryLogger::logToFile('database');

// Dump for debugging
QueryLogger::dump();

// Clear logged queries
QueryLogger::clear();

// Disable logging
QueryLogger::disable();
```

#### ModelUtility

[](#modelutility)

Useful model introspection methods:

```
use Bywyd\LaravelQol\Utilities\ModelUtility;

// Get table columns
$columns = ModelUtility::getTableColumns(User::class);

// Get fillable columns
$fillable = ModelUtility::getFillableColumns($user);

// Get hidden columns
$hidden = ModelUtility::getHiddenColumns($user);

// Get dirty (changed but not saved) attributes
$dirty = ModelUtility::getDirtyAttributes($user);

// Get changed attributes after save
$changes = ModelUtility::getChangedAttributes($user);

// Check if attribute exists
if (ModelUtility::hasAttribute($user, 'email')) {
    // ...
}

// Clone model
$clone = ModelUtility::cloneModel($user, ['id', 'created_at']);

// Get loaded relations
$relations = ModelUtility::getLoadedRelations($user);

// Check if relation is loaded
if (ModelUtility::isRelationLoaded($user, 'posts')) {
    // ...
}

// Diff two models
$diff = ModelUtility::diff($originalUser, $modifiedUser);
// Returns: ['email' => ['old' => 'old@example.com', 'new' => 'new@example.com']]
```

Usage Examples
--------------

[](#usage-examples)

### Example 1: API Controller with All Features

[](#example-1-api-controller-with-all-features)

```
use App\Models\Product;
use Bywyd\LaravelQol\Traits\ApiResponse;
use Bywyd\LaravelQol\Rules\StrongPassword;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    use ApiResponse;

    public function index(Request $request)
    {
        $query = Product::query();

        // Use CommonScopes
        if ($request->boolean('active_only')) {
            $query->active();
        }

        if ($search = $request->search('q')) {
            $query->whereLike($search, ['name', 'description']);
        }

        // Use Request macros for sorting
        $sort = $request->sort('created_at', 'desc');
        $query->orderBy($sort['column'], $sort['direction']);

        // Smart pagination
        $products = $query->smartPaginate();

        return $this->paginated($products, 'Products retrieved successfully');
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'price' => 'required|numeric|min:0',
            'is_active' => 'boolean',
        ]);

        $product = Product::create($validated);

        return $this->created($product, 'Product created successfully');
    }
}
```

### Example 2: Using Utilities for Performance Monitoring

[](#example-2-using-utilities-for-performance-monitoring)

```
use Bywyd\LaravelQol\Utilities\QueryLogger;

// In a middleware or service provider
if (app()->environment('local')) {
    QueryLogger::enable();

    app()->terminating(function () {
        if (QueryLogger::getCount() > 50) {
            logger()->warning('High query count detected', [
                'total_queries' => QueryLogger::getCount(),
                'total_time' => QueryLogger::getTotalTime(),
                'slowest' => QueryLogger::getSlowestQueries(5),
            ]);
        }
    });
}
```

### Example 3: Model with All Traits

[](#example-3-model-with-all-traits)

```
use Illuminate\Database\Eloquent\Model;
use Bywyd\LaravelQol\Traits\{
    HasHistory,
    HasRoles,
    HasSettings,
    HasUuid,
    HasSlug,
    HasStatus,
    Sortable,
    Cacheable,
    Searchable,
    CommonScopes
};

class Article extends Model
{
    use HasHistory,
        HasRoles,
        HasSettings,
        HasUuid,
        HasSlug,
        HasStatus,
        Sortable,
        Cacheable,
        Searchable,
        CommonScopes;

    protected $fillable = ['title', 'content', 'status'];
    protected $slugSource = 'title';
    protected $searchable = ['title', 'content'];

    // Now you have access to all features:
    // - History tracking
    // - Role-based permissions
    // - Per-model settings
    // - UUID primary key
    // - Auto-generated slugs
    // - Status management
    // - Sortable ordering
    // - Model caching
    // - Full-text search
    // - Query scopes
}

// Usage
$article = Article::create(['title' => 'My Article', 'content' => '...']);
$article->logHistory(HistoryLogTypes::CUSTOM, 'Published');
$article->setSetting('views_count', 0);
$articles = Article::active()->published()->thisMonth()->get();
```

Available Traits
----------------

[](#available-traits)

### Media Traits

[](#media-traits)

- **HasImages** - Image management with ordering, tagging, and URLs
- **HasFiles** - Generic file management with type detection
- **HasVideos** - Video management with metadata and thumbnails

### Model Enhancement Traits

[](#model-enhancement-traits)

- **HasHistory** - Automatic change tracking with old/new values
- **HasRoles** - Complete role &amp; permission system with middleware and Blade directives
- **HasIntegrations** - OAuth, API keys, and third-party service credentials
- **HasUuid** - Auto-generate UUIDs on model creation
- **HasSlug** - Auto-generate unique slugs from any field
- **HasStatus** - Active/inactive status management
- **Sortable** - Ordering and reordering functionality
- **Cacheable** - Model-level caching with auto-invalidation
- **Searchable** - Simple and full-text search

### Authorization System

[](#authorization-system)

- **Role Model** - Hierarchical roles with level-based access
- **Permission Model** - Granular permission control with groups
- **Route Middleware** - `role`, `permission`, `role_or_permission`
- **Blade Directives** - `@role`, `@permission`, `@hasanyrole`, etc.
- **Laravel Gates** - Auto-registered from permissions
- **Super Admin** - Wildcard permission support

Requirements
------------

[](#requirements)

- PHP 8.1 or higher
- Laravel 10.0 or higher

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE) for more information.

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance78

Regular maintenance activity

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~8 days

Total

6

Last Release

113d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e6fb24c8c43c74ed8f130f8085cbbb2643d3c9e138b012d8a3227f10339470fc?d=identicon)[bywyd](/maintainers/bywyd)

---

Top Contributors

[![bywyd](https://avatars.githubusercontent.com/u/76068077?v=4)](https://github.com/bywyd "bywyd (15 commits)")

---

Tags

laravelhelpersutilitiestraitsquality-of-life

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/bywyd-laravel-qol/health.svg)

```
[![Health](https://phpackages.com/badges/bywyd-laravel-qol/health.svg)](https://phpackages.com/packages/bywyd-laravel-qol)
```

###  Alternatives

[ronasit/laravel-helpers

Provided helpers function and some helper class.

1475.7k13](/packages/ronasit-laravel-helpers)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
