PHPackages                             aboleon/metaframework-support - 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. [Debugging &amp; Profiling](/categories/debugging)
4. /
5. aboleon/metaframework-support

ActiveLibrary[Debugging &amp; Profiling](/categories/debugging)

aboleon/metaframework-support
=============================

Laravel support package providing enhanced debugging helpers, AJAX request handling, and comprehensive response/message management utilities

1.6.1(2w ago)0275↓85.7%4MITPHPPHP ^8.3CI passing

Since Jan 12Pushed 1mo agoCompare

[ Source](https://github.com/aboleon/metaframework-support)[ Packagist](https://packagist.org/packages/aboleon/metaframework-support)[ RSS](/packages/aboleon-metaframework-support/feed)WikiDiscussions 1.x Synced 1w ago

READMEChangelogDependencies (30)Versions (17)Used By (4)

MetaFramework Support
=====================

[](#metaframework-support)

[![Tests](https://github.com/aboleon/metaframework-support/actions/workflows/tests.yml/badge.svg)](https://github.com/aboleon/metaframework-support/actions)[![codecov](https://camo.githubusercontent.com/2a7ae58f42961d6298e201f1f806325ab3b1609dc321c095ca9da9e6b363c152/68747470733a2f2f636f6465636f762e696f2f67682f61626f6c656f6e2f6d6574616672616d65776f726b2d737570706f72742f67726170682f62616467652e737667)](https://codecov.io/gh/aboleon/metaframework-support)[![Latest Version on Packagist](https://camo.githubusercontent.com/f9e9e4ccd528b3374cc512cf5e81f23b5deadd3366bafca3c1195bd05bd86092/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f61626f6c656f6e2f6d6574616672616d65776f726b2d737570706f72742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aboleon/metaframework-support)[![Total Downloads](https://camo.githubusercontent.com/b8b1093be9c83614ab5ff1ec6cd6f87dc16f40eb0351b7a9b94c39b4725b08b1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f61626f6c656f6e2f6d6574616672616d65776f726b2d737570706f72742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aboleon/metaframework-support)[![PHP Version](https://camo.githubusercontent.com/4fe14f52c1f92bc2adc326f867ffc260c7add87ff159d8ab48cf52c4f2e87ee6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f61626f6c656f6e2f6d6574616672616d65776f726b2d737570706f72742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aboleon/metaframework-support)[![License](https://camo.githubusercontent.com/95f2d515539be2d54496256a3d0ea6e7dae0256a82e498c490f4ba5dab8dac27/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f61626f6c656f6e2f6d6574616672616d65776f726b2d737570706f72742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/aboleon/metaframework-support)

A Laravel package providing essential utilities for debugging, AJAX handling, and standardized response management.

Features
--------

[](#features)

- Enhanced debugging helpers with beautiful output formatting
- AJAX request handling with automatic action dispatching
- Comprehensive response/message management system
- Flash message support
- Blade alert components
- SQL query debugging tools
- Opt-in Laravel log error email monitoring

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

[](#requirements)

- PHP ^8.3
- Laravel ^11.0, ^12.0, or ^13.0

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

[](#installation)

Install the package via Composer:

```
composer require aboleon/metaframework-support
```

The package will automatically register its service provider through Laravel's package discovery.

### Laravel Log Error Alerts

[](#laravel-log-error-alerts)

Enable the opt-in monitor to email newly appended `ERROR`, `CRITICAL`, `ALERT`, and `EMERGENCY` records from Laravel's standard text logs:

```
MFW_ERROR_ALERTS_ENABLED=true
MFW_ERROR_ALERTS_MAILER=smtp
```

When `MFW_ERROR_ALERTS_EMAIL` is omitted, the recipient defaults to Laravel's configured `mail.from.address` (`MAIL_FROM_ADDRESS`). Set `MFW_ERROR_ALERTS_EMAIL=alerts@example.com`only when alerts should go to a different address.

The package registers `mfw-support:send-error-alerts` with Laravel's scheduler every minute. The host must run `php artisan schedule:run` every minute.

The first execution initializes a file-and-byte cursor at the current end of the newest matching log, avoiding historical alerts. Later executions preserve multiline entries, finish a rotated log before reading its replacement, batch at most 20 errors per email, and commit the cursor only after successful synchronous delivery. Failed deliveries are retried on the next run. This provides at-least-once delivery for records successfully written to the configured Laravel log.

The Laravel `log` mail transport is rejected to prevent recursive alerts. Publish the configuration to customize paths, levels, batch size, schedule, or locking:

```
php artisan vendor:publish --tag=mfw-support-config
```

The monitor does not cover failures that prevent Laravel from writing a log or running its scheduler. Use an independent uptime/infrastructure monitor for PHP-FPM, Nginx, and host failures.

### Publishing Assets

[](#publishing-assets)

Publish the JavaScript assets to your public directory:

```
php artisan mfw-support:publish
```

Or use Laravel's vendor:publish command:

```
php artisan vendor:publish --tag=mfw-support-assets
```

This will copy the `mfw-ajax.js` and `mfw-action-client.js` files to `public/vendor/mfw-support/js/`.

**Include in your layout:**

```
{{-- In your layout file (e.g., resources/views/layouts/app.blade.php) --}}

```

**Publish assets with translations:**

```
php artisan mfw-support:publish --with-translations
```

**Force overwrite existing files:**

```
php artisan mfw-support:publish --force
```

### Publishing Translations

[](#publishing-translations)

The package includes translations for **English (en)**, **French (fr)**, and **Bulgarian (bg)**.

**Publish all translation files:**

```
php artisan mfw-support:publish-translations
```

**Publish specific language(s):**

```
php artisan mfw-support:publish-translations --lang=en --lang=fr
```

**Using Laravel's vendor:publish:**

```
# Publish only translations
php artisan vendor:publish --tag=mfw-support-translations

# Publish everything (assets + translations)
php artisan vendor:publish --tag=mfw-support
```

**Force overwrite existing translation files:**

```
php artisan mfw-support:publish-translations --force
```

Translations will be published to `lang/vendor/mfw-support/{locale}/mfw-support.php`.

### Svelte / Reactive Islands

[](#svelte--reactive-islands)

Use `mfwAction()` for JavaScript islands that need a Promise-based client instead of the DOM-mutating `mfwAjax()` flow. It posts to the same MetaFramework AJAX relay and injects the `action` parameter automatically:

```
const result = await mfwAction('saveSomething', new FormData(form), {
    url: 'panel/Publisher/ajax',
});
```

`mfwAction()` sends the CSRF token, requests JSON, throws `MfwActionError` for non-2xx responses, and dispatches response callbacks registered on `MfwActionClient`, `MfwAjax.callbacks`, or `window`.

For reactive UI feedback, use `MfwActionClient.submit()` instead of duplicating pending/error/message handling in each island:

```
const submitAction = MfwActionClient.createSubmitter({
    url: 'panel/Publisher/ajax',
    resultKey: 'thing',
    onResult: (thing) => applyResult(thing),
    onPending: (value) => pending = value,
    onAlerts: (value) => alerts = value,
});

await submitAction('saveSomething', formData, {
    pending: 'save',
});
```

The lower-level message normalizers are also available through `MfwActionFeedback`, `MfwActionClient`, and `MfwAjax` for custom or classic AJAX integrations.

Usage
-----

[](#usage)

### Debugging Helpers

[](#debugging-helpers)

The package provides global debugging functions with enhanced formatting:

#### `d($var, $varname = null)`

[](#dvar-varname--null)

Pretty-print a variable with styled output:

```
$user = User::find(1);
d($user, 'User Data');
```

#### `de($var, $varname = null)`

[](#devar-varname--null)

Debug and exit:

```
de($posts, 'All Posts');
// Script execution stops here
```

#### `dSql($query)`

[](#dsqlquery)

Debug Eloquent query with bindings:

```
$query = User::where('active', true)->where('role', 'admin');
dSql($query);
// Outputs: SELECT * FROM users WHERE active = 1 AND role = 'admin'
```

#### `deSql($query)`

[](#desqlquery)

Debug SQL query and exit:

```
deSql($query);
```

### Translations

[](#translations)

The package provides built-in translations for common error messages and AJAX responses.

#### Available Languages

[](#available-languages)

- **English (en)**
- **French (fr)**
- **Bulgarian (bg)**

#### Available Translation Keys

[](#available-translation-keys)

```
// AJAX error messages
__('mfw-support::mfw-support.ajax.request_cannot_be_interpreted')
__('mfw-support::mfw-support.ajax.request_cannot_be_processed')

// Generic error message
__('mfw-support::mfw-support.errors.error')
```

#### Using Translations

[](#using-translations)

The package automatically uses translations based on your application's locale. Set the locale in `config/app.php`:

```
'locale' => 'fr', // or 'en', 'bg'
```

Or change it dynamically:

```
app()->setLocale('fr');
```

#### Customizing Translations

[](#customizing-translations)

After publishing the translation files, you can customize them in:

```
lang/vendor/mfw-support/
├── en/
│   └── mfw-support.php
├── fr/
│   └── mfw-support.php
└── bg/
    └── mfw-support.php

```

**Example customization:**

```
// lang/vendor/mfw-support/en/mfw-support.php
return [
    'ajax' => [
        'request_cannot_be_interpreted' => 'Invalid request format.',
        'request_cannot_be_processed' => 'Unable to process this request.',
    ],
    'errors' => [
        'error' => 'Something went wrong!',
    ],
];
```

#### Adding New Languages

[](#adding-new-languages)

To add a new language, create a new directory in `lang/vendor/mfw-support/` with the locale code:

```
mkdir -p lang/vendor/mfw-support/es
```

Copy an existing translation file and translate:

```
cp lang/vendor/mfw-support/en/mfw-support.php lang/vendor/mfw-support/es/mfw-support.php
```

### AJAX Handling

[](#ajax-handling)

The `Ajax` trait provides powerful AJAX request handling with automatic action dispatching. The trait automatically enables AJAX mode, captures input, and routes requests to specific methods.

#### Setting Up an AJAX Controller

[](#setting-up-an-ajax-controller)

Create a dedicated AJAX controller using the `Ajax` trait:

```
use MetaFramework\Support\Traits\Ajax;

class AjaxController extends Controller
{
    use Ajax;

    // Each public method can be called via AJAX
    // The distribute() method from the trait handles routing automatically
}
```

#### Method Implementation Patterns

[](#method-implementation-patterns)

**Pattern 1: Delegating to Action Classes**

```
public function calculateTotal(): array
{
    return new PriceCalculator()
        ->ajaxMode()
        ->calculate()
        ->fetchResponse();
}

public function removeItem(): array
{
    return new CartController()
        ->ajaxMode()
        ->destroy((int)request('id'))
        ->fetchResponse();
}
```

**Pattern 2: Direct Implementation**

```
public function updateProfile(): array
{
    $user = User::find(request('user_id'));
    $user->update(request()->only(['name', 'email']));

    $this->responseSuccess('Profile updated successfully');
    $this->responseElement('user', $user);

    return $this->fetchResponse();
}
```

#### Frontend Integration

[](#frontend-integration)

The `distribute()` method automatically routes requests based on the `action` parameter:

```
// Route setup in web.php or api.php
Route::post('/ajax', [AjaxController::class, 'distribute']);

// Frontend AJAX call
fetch('/ajax', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
    },
    body: JSON.stringify({
        action: 'updateProfile',  // Maps to updateProfile() method
        user_id: 123,
        name: 'John Doe',
        email: 'john@example.com'
    })
})
.then(response => response.json())
.then(data => {
    if (data.error) {
        // Handle errors
        console.error(data.mfw_ajax_messages);
    } else {
        // Handle success
        console.log('Success:', data.mfw_ajax_messages);
    }
});
```

#### How It Works

[](#how-it-works)

1. Frontend sends POST request with `action` parameter
2. `distribute()` validates the action exists as a public method
3. Request is routed to the corresponding method
4. Method returns array response (automatically converted to JSON)
5. AJAX mode is automatically enabled with message handling

### Frontend JavaScript Integration

[](#frontend-javascript-integration)

The package provides a powerful `MfwAjax` JavaScript class and `mfwAjax()` helper function for seamless frontend-backend communication. This MetaFramework AJAX module handles requests with automatic message display and callback execution.

#### Setup

[](#setup)

The AJAX functionality requires jQuery. Make sure you've published the assets (see Installation section above), then include the file in your layout:

```
{{-- In your layout file --}}

```

Ensure you have the CSRF token meta tag in your ``:

```

```

Define the default AJAX route (optional):

```

```

#### The MfwAjax Class

[](#the-mfwajax-class)

The `MfwAjax` class handles all AJAX operations with automatic message display and callback execution.

**Requirements:** jQuery (uses `$.ajax`, `$.ajaxSetup`, and jQuery selectors)

**Static Properties:**

- `MfwAjax.dev` (boolean): Enable/disable debug mode (default: `true`)
- `MfwAjax.timerDefault` (number): Default animation timer in ms (default: `200`)

**Static Methods:**

- `MfwAjax.setVeil(container)`: Show loading overlay on a container
- `MfwAjax.removeVeil()`: Remove loading overlay
- `MfwAjax.spinout()`: Fade out and remove spinner elements

#### The mfwAjax() Helper Function

[](#the-mfwajax-helper-function)

**Signature:**

```
mfwAjax(formData, selector, options)
```

**Parameters:**

- `formData` (string): Serialized data in query string format (`action=method&param=value`)
- `selector` (jQuery): Element used to find `.messages` container and `data-ajax` attribute
- `options` (object): Optional configuration

**Available Options:**

- `spinner` (boolean): Show/hide loading spinner
- `successHandler` (function): Custom success callback (return `false` to suppress messages)
- `errorHandler` (function): Custom error callback (return `false` to suppress messages)
- `httpErrorHandler` (function): Callback receiving the jQuery XHR object when the request returns an HTTP error
- `keepMessages` (boolean): Keep previous messages instead of clearing them
- `printerOptions` (object):
    - `isDismissable` (boolean): Make alerts dismissable (default: `true`)
- `messagePrinter` (function): Custom message printer function

#### Primary Examples

[](#primary-examples)

```
// Basic usage
mfwAjax('action=deleteItem&id=123', $('#my-container'));
```

```
// With callback
mfwAjax('action=updateProfile&name=John&callback=refreshProfile', $('#profile-section'));
```

```
// With custom handlers
mfwAjax('action=saveData', $('#form'), {
    successHandler: function(result) {
        console.log('Success!', result);
        return true; // Show messages
    },
    errorHandler: function(result) {
        console.error('Error!', result);
        return false; // Suppress messages
    }
});
```

HTTP error responses automatically render `mfw_ajax_messages`, including rate-limit and authorization responses. Use `httpErrorHandler` for additional reporting without replacing the standard message display:

```
mfwAjax('action=saveData', $('#form'), {
    httpErrorHandler: function(xhr) {
        reportClientFailure(xhr.status);
    }
});
```

#### Secondary Example (Quick Usage)

[](#secondary-example-quick-usage)

```
// Simple AJAX call
mfwAjax('action=deleteItem&id=123', $('#container'));

// With callback
mfwAjax('action=updateProfile&name=John&callback=refreshProfile', $('#profile-section'));

function refreshProfile(result) {
    console.log('Profile updated!', result);
    // Update UI
    $('#username').text(result.name);
}
```

#### Using data-ajax Attribute

[](#using-data-ajax-attribute)

The `mfwAjax()` function automatically detects the AJAX endpoint from the `data-ajax` attribute:

```

    {{-- Content --}}

```

```
// AJAX URL is automatically picked from data-ajax attribute
mfwAjax('action=deleteNote&id=456', $('#notes'));
```

#### Complete Real-World Example

[](#complete-real-world-example)

**Blade Template:**

```
@extends('layouts.app')

@section('content')
    {{-- Flash messages from session --}}

            @foreach($notes as $note)

                    {{ $note->content }}

                        Delete

            @endforeach

        Add Note

@endsection

@push('js')

    function deleteNoteCallback(result) {
        if (!result.error) {
            // Remove the note from DOM
            $('.note[data-id="' + result.input.id + '"]').fadeOut(function() {
                $(this).remove();
            });
        }
    }

    function addNoteCallback(result) {
        if (!result.error) {
            // Prepend new note to the list
            $('#notes').prepend(result.html);
        }
    }

    $(document).ready(function() {
        // Delete note
        $(document).on('click', '.delete-note', function() {
            const noteId = $(this).data('note-id');
            mfwAjax(
                'action=deleteNote&id=' + noteId + '&callback=deleteNoteCallback',
                $('#note-messages')
            );
        });

        // Add note
        $('#add-note').on('click', function() {
            const content = prompt('Enter note content:');
            if (content) {
                mfwAjax(
                    'action=addNote&content=' + encodeURIComponent(content) + '&callback=addNoteCallback',
                    $('#note-messages')
                );
            }
        });
    });

@endpush
```

**Controller:**

```
use MetaFramework\Support\Traits\Ajax;

class AjaxController extends Controller
{
    use Ajax;

    public function deleteNote(): array
    {
        $note = Note::findOrFail(request('id'));
        $note->delete();

        $this->responseSuccess('Note deleted successfully');

        return $this->fetchResponse();
    }

    public function addNote(): array
    {
        $note = Note::create([
            'content' => request('content'),
            'user_id' => auth()->id()
        ]);

        $this->responseSuccess('Note added successfully');
        $this->responseElement('html', view('partials.note', compact('note'))->render());

        return $this->fetchResponse();
    }
}
```

#### Advanced Options Example

[](#advanced-options-example)

```
mfwAjax('action=processData&id=123', $('#form'), {
    successHandler: function(result) {
        console.log('Custom success handling', result);
        // Return false to suppress automatic message display
        return false;
    },
    errorHandler: function(result) {
        console.error('Custom error handling', result);
        // Return true to show automatic messages
        return true;
    },
    keepMessages: true, // Don't clear previous messages
    printerOptions: {
        isDismissable: false // Make alerts non-dismissable
    }
});
```

#### Response Structure

[](#response-structure)

The AJAX response from your controller methods includes:

```
{
    "error": false,                    // true if there's an error
    "mfw_ajax_messages": [             // Messages array
        {"success": "Operation successful"},
        {"info": "Additional information"}
    ],
    "callback": "callbackFunctionName", // Auto-captured from request
    "input": {                          // Original request data
        "action": "deleteNote",
        "id": 123
    },
    // ... any custom data you added with responseElement()
    "custom_field": "custom_value"
}
```

#### Helper Methods

[](#helper-methods)

**MfwAjax.setVeil(container)** - Show loading overlay:

```
MfwAjax.setVeil($('#my-container'));
```

**MfwAjax.removeVeil()** - Remove loading overlay:

```
MfwAjax.removeVeil();
```

### Response Management

[](#response-management)

The `Responses` trait provides a powerful system for managing messages and responses:

```
use MetaFramework\Support\Traits\Responses;

class OrderController extends Controller
{
    use Responses;

    public function store(Request $request)
    {
        try {
            // Create order
            $order = Order::create($request->all());

            $this->responseSuccess('Order created successfully');
            $this->responseElement('order_id', $order->id);

            $this->redirectRoute('orders.show', $order->id);

        } catch (\Exception $e) {
            $this->responseException($e, 'Failed to create order');
        }

        return $this->sendResponse();
    }
}
```

#### Available Response Methods

[](#available-response-methods)

```
// Success messages
$this->responseSuccess('Operation completed');

// Error messages
$this->responseError('Something went wrong');

// Warning messages
$this->responseWarning('This action cannot be undone');

// Info messages
$this->responseNotice('FYI: This is informational');

// Debug messages (only visible to developers)
$this->responseDebug($data, 'Debug Info');

// Add custom data to response
$this->responseElement('user', $user);
$this->responseElement('total', 150);

// Exception handling with auto-reporting
$this->responseException($exception, 'Custom error message');
```

#### Flash Messages

[](#flash-messages)

```
// Flash response to session
$this->flashResponse();

// Retrieve in view
@if(session('session_response'))
    {!! MetaFramework\Support\Responses\ResponseMessages::parseResponse(session('session_response')) !!}
@endif
```

#### Response Modes

[](#response-modes)

```
// Enable AJAX mode
$this->enableAjaxMode();

// Disable messages
$this->disableMessages();

// Keep errors even in debug mode
$this->keepErrors();

// Console logging mode
$this->consoleLog();
```

### Alert Component

[](#alert-component)

Use the Blade alert component to display messages:

```

```

Available types: `success`, `danger`, `warning`, `info`

### Response &amp; Validation Components

[](#response--validation-components)

Use the Blade components to display session responses and validation feedback:

```
{{-- Flash/session response messages --}}

{{-- Validation error list --}}

{{-- Validation banner notice --}}

```

You can also customize the response messages container:

```

```

### Response Message Parsing

[](#response-message-parsing)

Parse and display response arrays automatically:

```
use MetaFramework\Support\Responses\ResponseMessages;

// In your view
{!! ResponseMessages::parseResponse(session('session_response')) !!}

// Display validation errors
{!! ResponseMessages::validationErrors($errors) !!}

// Individual alert types
{!! ResponseMessages::successNotice('Success!') !!}
{!! ResponseMessages::criticalNotice('Error!') !!}
{!! ResponseMessages::warningNotice('Warning!') !!}
{!! ResponseMessages::infoNotice('Info') !!}
```

Advanced Examples
-----------------

[](#advanced-examples)

### Complete CRUD Controller Example

[](#complete-crud-controller-example)

```
use MetaFramework\Support\Traits\Responses;

class PostController extends Controller
{
    use Responses;

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|max:255',
            'content' => 'required'
        ]);

        try {
            $post = Post::create($validated);

            $this->responseSuccess('Post created successfully');
            $this->redirectRoute('posts.show', $post->id);

            return $this->sendResponse();

        } catch (\Exception $e) {
            $this->responseException($e);
            $this->redirectRoute('posts.index');

            return $this->sendResponse();
        }
    }

    public function destroy(Post $post)
    {
        if ($post->published) {
            $this->responseWarning('Cannot delete published posts');
            return $this->sendResponse();
        }

        $post->delete();

        $this->responseSuccess('Post deleted successfully');
        $this->redirectRoute('posts.index');

        return $this->sendResponse();
    }
}
```

### AJAX with Callbacks

[](#ajax-with-callbacks)

The Ajax trait automatically captures callback parameters sent from the frontend:

```
use MetaFramework\Support\Traits\Ajax;

class AjaxController extends Controller
{
    use Ajax;

    public function markAsRead(): array
    {
        $notification = Notification::find(request('id'));
        $notification->markAsRead();

        $this->responseSuccess('Notification marked as read');
        $this->responseElement('unread_count', auth()->user()->unreadNotifications->count());

        // callback is automatically included if sent from frontend
        return $this->fetchResponse();
    }
}
```

```
// Route: Route::post('/ajax', [AjaxController::class, 'distribute']);

fetch('/ajax', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-TOKEN': token
    },
    body: JSON.stringify({
        action: 'markAsRead',
        id: 123,
        callback: 'updateBadge'  // Automatically captured by Ajax trait
    })
})
.then(response => response.json())
.then(data => {
    // Execute callback if provided
    if (data.callback && typeof window[data.callback] === 'function') {
        window[data.callback](data);
    }

    // Or handle messages
    if (data.mfw_ajax_messages) {
        data.mfw_ajax_messages.forEach(msg => {
            Object.entries(msg).forEach(([type, message]) => {
                console.log(`${type}: ${message}`);
            });
        });
    }
});

function updateBadge(data) {
    document.querySelector('.badge').textContent = data.unread_count;
}
```

License
-------

[](#license)

MIT License

Support
-------

[](#support)

For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/aboleon/metaframework-support).

###  Health Score

48

—

FairBetter than 94% of packages

Maintenance94

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity58

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 ~12 days

Total

17

Last Release

19d ago

Major Versions

0.x-dev → 1.0.02026-01-28

### Community

Maintainers

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

---

Top Contributors

[![aboleon](https://avatars.githubusercontent.com/u/86931678?v=4)](https://github.com/aboleon "aboleon (16 commits)")

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/aboleon-metaframework-support/health.svg)

```
[![Health](https://phpackages.com/badges/aboleon-metaframework-support/health.svg)](https://phpackages.com/packages/aboleon-metaframework-support)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.6k31.8M160](/packages/laravel-cashier)[tallstackui/tallstackui

TallStackUI is a powerful suite of Blade components that elevate your workflow of Livewire applications.

731189.9k16](/packages/tallstackui-tallstackui)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

79227.1M227](/packages/laravel-mcp)[laravel/ai

The official AI SDK for Laravel.

1.1k4.6M319](/packages/laravel-ai)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45844.8k1](/packages/pressbooks-pressbooks)

PHPackages © 2026

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