PHPackages                             zephyr-it/shared - 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. zephyr-it/shared

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

zephyr-it/shared
================

Shared traits, report pages, and utilities for Zephyr-IT modular applications.

01271[6 PRs](https://github.com/zephyr-it/shared/pulls)PHPCI passing

Since Oct 13Pushed 1mo agoCompare

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

READMEChangelogDependenciesVersions (8)Used By (0)

🌐 Zephyr Shared Package
=======================

[](#-zephyr-shared-package)

[![Latest Version on Packagist](https://camo.githubusercontent.com/62f66fff9e3358c27bb7a9eb6b163c67c4595ab4198edd23d348e2c758e68efe/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7a65706879722d69742f7368617265642e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/zephyr-it/shared)[![GitHub Tests Status](https://camo.githubusercontent.com/2e3ca2bff1a1a6b9cc79e031ede199f9e02809591ae8cc4e8f2b3258121fbbcd/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7a65706879722d69742f7368617265642f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/zephyr-it/shared/actions?query=workflow%3Arun-tests+branch%3Amain)[![Code Style Status](https://camo.githubusercontent.com/6fb2cffed67c8a1c26a1e4ecee6bbeeb7ab87b7d18a0ede80d4f015054fd93cd/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7a65706879722d69742f7368617265642f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/zephyr-it/shared/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/6b7a3fa722216c13c915efa9c5d8d95066db877b9520136da9a067a3fd1d3739/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7a65706879722d69742f7368617265642e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/zephyr-it/shared)

**Zephyr Shared** is a foundational package that delivers shared logic, UI components, and developer tools across all Zephyr-IT modular Laravel applications.

It provides:

- A reusable `BasePlugin` system for Filament v3 (auto-register pages, resources, widgets)
- Pre-configured Filament resources: Country, State, and City
- Export architecture for multi-sheet Excel reports using Laravel Excel
- A CLI script to check for missing language keys
- Centralized helpers, traits, and support classes for common functionality

📑 Table of Contents
-------------------

[](#-table-of-contents)

- [Installation](#installation)
- [Usage](#usage)
- [Excel Report Exports](#excel-report-exports)
- [Global Helper Functions](#global-helper-functions)
- [Model Concerns](#model-concerns)
- [UniqueEncryptedRule](#uniqueencryptedrule)
- [Smart Seeding System with BaseSeeder](#smart-seeding-system-with-baseseeder)
- [Useful Shared Traits](#useful-shared-traits)
- [Dynamic Metrics Engine](#dynamic-metrics-engine)
- [How to Use](#how-to-use)
- [Helper Methods (Internal Use)](#helper-methods-internal-use)
- [Testing](#testing)
- [Changelog](#changelog)
- [Contributing](#contributing)
- [Security](#security)
- [Credits](#credits)
- [License](#license)

---

📦 Installation
--------------

[](#-installation)

Install via Composer:

```
composer require zephyr-it/shared
```

---

🚀 Usage
-------

[](#-usage)

### ⚙️ Run the Shared Installer

[](#️-run-the-shared-installer)

After installing the package, publish all shared configuration files, assets, migrations, and utilities by running:

```
php artisan shared:install
```

This command will:

- Publish shared configs, views, migrations, and scripts
- Publish third-party assets like `spatie/laravel-activitylog` migrations
- Prompt you to run `php artisan migrate`

To overwrite existing files:

```
php artisan shared:install --force
```

> ℹ️ This is the preferred way to initialize the shared stack within any Laravel application or module using Zephyr-IT’s architecture.

---

📤 Excel Report Exports
----------------------

[](#-excel-report-exports)

This package offers a powerful and flexible foundation for building multi-sheet Excel reports using [Laravel Excel (maatwebsite/excel)](https://laravel-excel.com).

With built-in support for:

- 🎨 Styled sheets and column formatting
- 📚 Auto-generated legends and notes
- 🎯 Custom filters, headings, and merged cells
- 📊 Modular architecture for reusable reporting logic

> ✅ Laravel Excel is already required. No additional setup is necessary.

---

### 🧱 Base Export Classes

[](#-base-export-classes)

#### 🧾 `BaseSheet`

[](#-basesheet)

Defines a single Excel sheet. Implements:

- `FromCollection`, `WithHeadings`, `WithStyles`
- `WithEvents`, `WithTitle`, `WithColumnFormatting`
- `ShouldQueue`, `ShouldAutoSize`

Ideal for building modular, stylized reports.

#### 🗃️ `AbstractReportExport`

[](#️-abstractreportexport)

Used to group and manage multiple `BaseSheet` instances. Also provides integrated date range parsing via the `HasDateRangeParser` trait.

```
new CompanyUsersExport(
    $company,
    '2024-01-01 - 2024-01-31',
    $extraContext
);
```

---

### 🛠 BaseSheet Constructor Example

[](#-basesheet-constructor-example)

```
new UsersSheet(
    title: 'Users',
    data: $collection,
    headings: ['ID', 'Name'],
    headerColor: '1E88E5',
    legendRows: [['Column', 'Details']],
    legendStyles: [],
    columnWidths: ['A' => 15, 'B' => 30],
    mergeCells: ['A1:C1'],
    rowStyles: [],
    applyBorders: true,
    freezeHeader: true,
    useAutoFilter: true,
    enableLogging: true,
    notesRow: 'Data generated from system.'
)
```

---

### 🧩 Feature Breakdown

[](#-feature-breakdown)

FeatureDescription`notesRow`Adds an intro row above headings for metadata or descriptions`legendRows`Displays a table legend for context (e.g., column definitions)`legendStyles`Style individual cells in the legend`columnWidths`Specify manual widths for columns`mergeCells`Merge specific cell ranges`rowStyles`Apply font, color, or alignment styles to specific rows`headerColor`Adds a background color and white text to the heading row`useAutoFilter`Enables Excel dropdown filters on the heading row`freezeHeader`Locks the top row while scrolling`enableLogging`Logs export metadata to `storage/logs/laravel.log`---

### 🎨 Extending Styles and Formats

[](#-extending-styles-and-formats)

You can override `columnFormats()` and `styles()` in your custom sheet:

```
public function columnFormats(): array
{
    return [
        'C' => '#,##0.00',
        'D' => 'dd-mm-yyyy',
    ];
}

public function styles(Worksheet $sheet): array
{
    return [
        2 => ['font' => ['bold' => true]],
    ];
}
```

---

### 🧵 Advanced Customization

[](#-advanced-customization)

Override `registerEvents()` in your `BaseSheet` class to:

- Customize borders
- Dynamically merge cells
- Alter freeze pane logic
- Inject `notesRow` or `legendRows` conditionally

---

### ✅ Full Export Flow

[](#-full-export-flow)

#### Step 1: Define the Sheet

[](#step-1-define-the-sheet)

```
class UsersSheet extends BaseSheet
{
    public function columnFormats(): array
    {
        return ['C' => '#,##0.00'];
    }
}
```

#### Step 2: Create the Export

[](#step-2-create-the-export)

```
class CompanyUsersExport extends AbstractReportExport
{
    public function sheets(): array
    {
        return [
            new UsersSheet(
                title: 'Users',
                data: $this->entity->users->map(fn ($u) => [$u->id, $u->name, $u->balance]),
                headings: ['ID', 'Name', 'Balance'],
                notesRow: 'This report shows active users only.',
                legendRows: [['Balance', 'User’s current account balance']],
            )
        ];
    }
}
```

#### Step 3: Trigger the Export

[](#step-3-trigger-the-export)

Immediate download:

```
return Excel::download(
    new CompanyUsersExport($company, 'this_month'),
    'company-users.xlsx'
);
```

Queued export:

```
Excel::queue(
    new CompanyUsersExport($company, 'last_30_days'),
    'exports/company.xlsx'
);
```

---

### 📦 Real-World Use Cases

[](#-real-world-use-cases)

- Export buttons on Filament table listings
- Scheduled exports via Laravel scheduler
- Admin and compliance reporting
- API-based report generators
- Multi-sheet financial summaries
- Dynamic data audits filtered by date range

---

### 📚 Filament Base

[](#-filament-base)

### 🔌 Creating a Modular Filament Plugin

[](#-creating-a-modular-filament-plugin)

Zephyr Shared provides a powerful `BasePlugin` class to streamline plugin development for Filament v3. It enables clean, modular registration of your Pages, Resources, and Widgets — all based on convention.

#### 🚀 What `BasePlugin` Does

[](#-what-baseplugin-does)

- ✅ Auto-registers Filament components via reflection
- ✅ Detects correct namespaces and directories based on file location
- ✅ Keeps plugin definitions DRY and declarative
- ✅ Supports toggling discovery for Pages, Widgets, and Resources

---

#### 🧪 Register in Filament Panel

[](#-register-in-filament-panel)

To enable your plugin in the Filament panel:

```
use ZephyrIt\Accounts\Filament\SharedPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(SharedPlugin::make());
}
```

---

#### ⚙️ Optional Discovery Controls

[](#️-optional-discovery-controls)

Want to skip registering specific components?

```
SharedPlugin::make()
    ->registerPages(false)
    ->registerWidgets(false);
```

---

By using `BasePlugin`, all your Zephyr module plugins remain:

- ✅ Clean
- ✅ Auto-wired
- ✅ Convention-driven
- ✅ Consistently modular

---

### 📊 Creating a Report Page with Filters

[](#-creating-a-report-page-with-filters)

Zephyr Shared includes a `ReportPage` base class to help you rapidly scaffold Filament-powered dashboard pages — complete with filters, permissions, and layout.

---

### ✅ Built-In Features

[](#-built-in-features)

When extending `ReportPage`, you automatically get:

- 📅 A date range picker with today’s date as the default
- 🧭 Navigation label and title via `titleKey`
- 🗂 Grouping via `getNavigationGroup()`
- 🧱 Layout managed by Filament’s dashboard base
- 🔍 Optional custom filters via `getFilterFormSchema()`
- 🔐 Role-based access control with `HasPageShield`

---

🧠 Global Helper Functions
-------------------------

[](#-global-helper-functions)

All helpers are available globally from `src/Helpers/bootstrap_helpers.php`.

---

### 🔢 `FormatHelpers`

[](#-formathelpers)

```
numberToIndianFormat(1234567);      // "12,34,567"
numberToWord(123);                  // "one hundred twenty-three"
formatNumberShort(1500000);         // "1.5M"
formatAddButtonLabel('User');       // "Add User"
formatCopyMessage('Email');         // "Copied Email"
```

---

### 🧵 `StringHelpers`

[](#-stringhelpers)

```
sanitizeAndFormat('John DOE');      // "John Doe"
sanitizeSpecialCharacters('Hey#$', ' ') // "Hey"
normalizeString('Ärgerlich');       // "Argerlich"
```

---

### 🧬 `EnumHelpers`

[](#-enumhelpers)

```
getEnumValues(StatusEnum::class);   // ['active', 'inactive']
getEnumLabels(StatusEnum::class);   // ['active' => 'Active', ...]
getFilteredEnumStatuses(StatusEnum::class, ['archived']);
```

---

### 📦 `ModuleHelpers`

[](#-modulehelpers)

```
getActiveModules();                 // ['cms', 'hrm', 'insurance']
getModuleModels('cms');            // ['Page', 'Post']
getAllModelPaths();
getModuleNamespace('cms');         // App\Modules\Cms
clearModuleCache();
```

---

### 🧩 `ModelHelpers`

[](#-modelhelpers)

```
getAllModelClasses();               // Fully-qualified class names
resolveFieldCast(User::class, 'email');  // 'string'
getLastRecord(User::class, 'created_at'); // Latest created user
```

---

### 🧰 `GeneratorHelpers`

[](#-generatorhelpers)

```
generateUniqueNumber(User::class, 'USR', 'code');  // "USR/2025/001"
generateYears(2000, 2025);                         // [2000, ..., 2025]
getClassesFromDirectory(app_path('Models'), 'App\\Models');
```

---

### 💸 `ApplicationHelpers`

[](#-applicationhelpers)

```
getCurrencySymbol();               // ₹
getDenominationsArray('currency');
transformSupportedLocales();       // ['en' => 'English', ...]
```

---

### ⚙️ `InstallHelper` Functions

[](#️-installhelper-functions)

> Used in commands and setup logic

```
install_publish($this, [['tag' => 'toolkit-config']]);
install_publish_files($this, base_path('publish'));
install_publish_migrations($this, base_path('migrations'));
```

---

### 📄 `BaseModel`

[](#-basemodel)

A foundational Eloquent model that serves as the base for all Zephyr-IT models.

#### ✅ Key Features

[](#-key-features)

- Auto-tracks `fillable` changes using `Spatie\Activitylog`
- Lifecycle control via `HasLifecycleHooks`
- Easily extended with shared scopes (`HasCommonScopes`)

```
use ZephyrIt\Shared\Models\BaseModel;
use Spatie\Activitylog\LogOptions;

class Invoice extends BaseModel
{
    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->logFillable()
            ->logOnlyDirty();
    }
}
```

---

### 👤 `BaseAuthModel`

[](#-baseauthmodel)

Extends Laravel's `Authenticatable` with the same lifecycle behaviors.

#### 🛠 Use It For:

[](#-use-it-for)

- `User`, `Admin`, `Staff`, or other models with Laravel Auth

```
use ZephyrIt\Shared\Models\BaseAuthModel;

class Staff extends BaseAuthModel
{
    // Includes auth + lifecycle logic
}
```

---

🧩 Model Concerns
----------------

[](#-model-concerns)

---

### 🧬 `HasLifecycleHooks`

[](#-haslifecyclehooks)

Encapsulates transactional lifecycle control for Eloquent model events.

#### 🔧 Key Features

[](#-key-features-1)

- Wraps create/update/save/delete/restore in DB transactions
- Uses simple overridable methods for each lifecycle phase
- Supports automatic cascade delete/restore for relationships

---

#### 🔁 Soft Delete Cascade

[](#-soft-delete-cascade)

Enable cascade delete/restore on related models:

```
protected bool $shouldSyncRelatedSoftDeletes = true;

protected function relatedModelsForSoftDelete(): array
{
    return ['tasks', 'comments'];
}
```

---

#### ✨ Lifecycle Hook Methods

[](#-lifecycle-hook-methods)

You can override any of the following:

```
protected function performCreating(): void {}
protected function performAfterCreate(): void {}

protected function performUpdating(): void {}
protected function performAfterUpdate(): void {}

protected function performSaving(): void {}
protected function performAfterSave(): void {}

protected function performDeleting(): void {}
protected function performAfterDelete(): void {}

protected function performRestoring(): void {}
protected function performAfterRestore(): void {}
```

> All methods are optional — define only what you need.

---

#### ✅ Example Usage

[](#-example-usage)

```
use ZephyrIt\Shared\Models\BaseModel;

class Invoice extends BaseModel
{
    protected bool $shouldSyncRelatedSoftDeletes = true;

    protected function relatedModelsForSoftDelete(): array
    {
        return ['lineItems'];
    }

    public function lineItems()
    {
        return $this->hasMany(LineItem::class);
    }

    protected function performAfterUpdate(): void
    {
        AuditLogger::log("Invoice {$this->id} was updated.");
    }
}
```

---

### 🔍 `HasCommonScopes`

[](#-hascommonscopes)

A collection of reusable and schema-safe Eloquent query scopes.

#### 🧠 Purpose

[](#-purpose)

- Add common filtering, searching, and ordering methods
- Skip queries safely if the expected column doesn’t exist
- Ideal for multi-tenant or optional schema scenarios

---

#### 🔐 Column Guard

[](#-column-guard)

Every scope uses `hasColumn()` internally:

```
protected function hasColumn(Builder $query, string $column): bool
```

Ensures the query only runs if the column is present.

---

#### 🧰 Available Scopes

[](#-available-scopes)

ScopeDescription`active()``is_active = true` (safe fallback)`inactive()``is_active = false``whereBoolean()`Generic boolean filter with column check`whereStatus()`Filters by a `status` value`ordered()`Order by any column + direction`recent()`Order by `created_at DESC``latestFirst()`Most recent records by any column`oldestFirst()`Oldest records by any column`search()`LIKE %term% search on a single column---

#### ✅ Example Usage

[](#-example-usage-1)

```
User::active()
    ->whereStatus('verified')
    ->search('email', 'example.com')
    ->latestFirst()
    ->get();
```

Each scope checks for the existence of the target column — meaning no more "column not found" errors in evolving or modular schemas.

---

🔒 `UniqueEncryptedRule`
-----------------------

[](#-uniqueencryptedrule)

This custom validation rule ensures **encrypted fields remain unique** across your models — even when stored as ciphertext.

It is designed specifically for cases where traditional `unique:` validation can't compare encrypted values in the database.

---

### ✅ When to Use It

[](#-when-to-use-it)

- You store fields like `email`, `phone`, or `SSN` encrypted in the DB
- You need to prevent duplicate entries without decrypting every row
- You want secure validation while editing (excluding the current model)

---

### 🧪 Example Usage

[](#-example-usage-2)

#### Standalone instantiation:

[](#standalone-instantiation)

```
use ZephyrIt\Shared\Rules\UniqueEncryptedRule;

new UniqueEncryptedRule(User::class, 'email', $this->user, 'name');
```

- `User::class` — target model
- `'email'` — encrypted column
- `$this->user` — optional current model (for edit forms)
- `'name'` — optional display column for error messages

---

#### In a Form Request:

[](#in-a-form-request)

```
public function rules(): array
{
    return [
        'email' => [
            'required',
            new UniqueEncryptedRule(User::class, 'email', $this->user),
        ],
    ];
}
```

---

### 🌍 Localization Message

[](#-localization-message)

Add this to your `resources/lang/en/messages.php` file to customize the validation error:

```
'unique_encrypted' => 'The :attribute already exists (used by :existing).',
```

> `:existing` will be replaced with the value from the optional "display column" (like `name` or `email`)

---

🌱 Smart Seeding System with `BaseSeeder`
----------------------------------------

[](#-smart-seeding-system-with-baseseeder)

The `BaseSeeder` class provides a **safe, idempotent, and environment-aware seeding entrypoint** for Zephyr-IT applications. It is used at the top level (`DatabaseSeeder`) to orchestrate and manage all module and development seeders.

> ❗ Module-specific seeders (e.g. `AccountsSeeder`, `UserSeeder`) should extend the default `Illuminate\Database\Seeder`, not `BaseSeeder`.

---

### ✅ Key Features

[](#-key-features-2)

- 📓 Logs seeder runs in the `seed_log` table to prevent duplicate execution
- ♻️ Automatically suppresses `spatie/laravel-activitylog` during seeding
- ⚙️ Smart `run()` logic that separates production vs. development seeders
- 🔁 Nested seeding supported via Laravel’s native `$this->call()` system

---

### 🔧 Setup

[](#-setup)

Ensure the `seed_log` tracking table exists by running the shared installer:

```
php artisan shared:install
php artisan migrate
```

> **Note** Avoid using `vendor:publish` directly. The `shared:install` command handles publishing migrations and other assets in a single step.

---

### 🧪 Actual Usage Pattern

[](#-actual-usage-pattern)

#### ✅ `DatabaseSeeder` using `BaseSeeder`

[](#-databaseseeder-using-baseseeder)

```
namespace Database\Seeders;

use ZephyrIt\Shared\Support\BaseSeeder;
use ZephyrIt\Shared\Database\Seeders\WorldDatabaseSeeder;

class DatabaseSeeder extends BaseSeeder
{
    public function run(): void
    {
        $this->command->info('🔄 Starting database seeding...');

        $baseSeeders = [
            WorldDatabaseSeeder::class,
            ShieldSeeder::class,
            UserSeeder::class,
            PlanSeeder::class,
            FeatureSeeder::class,
            ProductSeeder::class,
        ];

        $developmentSeeders = [
            TenantSeeder::class,
            // Add other dev/test seeders here
        ];

        $seeders = app()->isProduction()
            ? $baseSeeders
            : array_merge($baseSeeders, $developmentSeeders);

        $this->call($seeders);

        $this->command->info('✔ Database seeding completed.');
    }
}
```

---

#### ❌ `AccountsSeeder` — does NOT extend `BaseSeeder`

[](#-accountsseeder--does-not-extend-baseseeder)

```
namespace ZephyrIt\Accounts\Database\Seeders;

use Illuminate\Database\Seeder;

class AccountsSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([
            AccountTypeSeeder::class,
            DefaultAccountsSeeder::class,
        ]);
    }
}
```

This pattern keeps your module seeders lightweight and clean, using Laravel's core `Seeder` class.

---

### ✅ Running Seeders

[](#-running-seeders)

To run shared or environment-specific seeders via `DatabaseSeeder`:

```
php artisan db:seed
```

To run a specific one:

```
php artisan db:seed --class="ZephyrIt\Shared\Database\Seeders\WorldDatabaseSeeder"
```

---

### 🔁 Benefits of `BaseSeeder`

[](#-benefits-of-baseseeder)

- 🛡 Prevents duplicate seed execution using `seed_log`
- 🧘 Auto-suppresses activity logs during seeding
- 🔄 Restores log state even if an exception occurs
- 🧵 Supports full project orchestration without touching module logic

---

🎨 Useful Shared Traits
----------------------

[](#-useful-shared-traits)

These traits help you keep your services, charts, and multi-tenant logic **modular, DRY, and production-ready** across Zephyr-IT modules.

---

### 1️⃣ `ColorPaletteTrait`

[](#1️⃣-colorpalettetrait)

Dynamically generate a consistent color palette for charts (e.g. Chart.js, ApexCharts) with fallback to random RGBA values.

#### ✅ Features

[](#-features)

- Returns an array of RGBA strings with optional opacity
- Ensures visual consistency using preconfigured base colors
- Auto-fills additional entries with randomized color variants

#### ✅ Example Usage

[](#-example-usage-3)

```
use ZephyrIt\Shared\Traits\ColorPaletteTrait;

class RevenueChartService
{
    use ColorPaletteTrait;

    public function getChartColors(int $count): array
    {
        return $this->getColors($count);
    }
}
```

#### 🖼️ Sample Output

[](#️-sample-output)

```
[
    'backgroundColor' => ['rgba(255, 99, 132, 0.7)', 'rgba(54, 162, 235, 0.7)', ...],
    'borderColor' => ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', ...],
]
```

This array can be injected directly into chart configuration objects.

---

### 2️⃣ `DeterminesTenant`

[](#2️⃣-determinestenant)

Resolves the current tenant based on the domain, using the `stancl/tenancy` package.

#### ✅ Features

[](#-features-1)

- Reads the current domain via `request()->getHost()`
- Queries the `domains` table to find the matching `Tenant`
- Returns the resolved tenant model — or `null` if not found

#### ✅ Example Usage

[](#-example-usage-4)

```
use ZephyrIt\Shared\Traits\DeterminesTenant;

class TenantAwareReportService
{
    use DeterminesTenant;

    public function getTenantName(): ?string
    {
        return optional($this->determineTenant())->name;
    }
}
```

#### 💡 Safe for CLI Use

[](#-safe-for-cli-use)

Returns `null` if `php artisan` is running (e.g. in queue workers, commands, or test runners).

---

### 3️⃣ `HasDateRangeParser`

[](#3️⃣-hasdaterangeparser)

A smart, flexible parser for handling UI-driven or backend-passed date ranges in a clean, uniform format.

#### ✅ Example Usage

[](#-example-usage-5)

```
[$start, $end] = $this->parseDateRange('2024-05-01 - 2024-05-31');

[$from, $to] = $this->parseDateRangeAsStrings(['01/05/2024', '31/05/2024']);
```

#### 🗂️ Supported Input Formats

[](#️-supported-input-formats)

- `'2024-05-01 - 2024-05-31'` (string range)
- `['2024-05-01', '2024-05-31']` (array of ISO dates)
- `['01/05/2024', '31/05/2024']` (array of D/M/Y format)

This trait is extremely useful for:

- Report filtering
- Dashboard widgets
- Scheduled exports
- API endpoints expecting flexible date inputs

---

📊 Dynamic Metrics Engine
------------------------

[](#-dynamic-metrics-engine)

The `DynamicMetricsTrait` provides a flexible, powerful way to **aggregate, filter, and chart dynamic data metrics** across any set of models. It is ideal for use in Filament dashboards, admin reports, and time-based insights.

---

### ✅ Key Features

[](#-key-features-3)

- Aggregate metrics (sum, count, list, avg) over time
- Group by single or nested keys (e.g., date → user → status)
- Chart-ready structure with interval-aware logic (daily/weekly/monthly)
- Optional `Closure`-based filters and dynamic groupings
- Works across multiple models in a single call

---

🚀 How to Use
------------

[](#-how-to-use)

### 1️⃣ `fetchDynamicMetricsData()`

[](#1️⃣-fetchdynamicmetricsdata)

Fetches grouped, nested metric results across a time range.

```
$results = $this->fetchDynamicMetricsData(
    models: [Invoice::class, Payment::class],
    metrics: [
        'total_amount' => ['amount', 'sum'],
        'avg_settlement_days' => ['registered_date', 'avg', fn ($group) => $group->whereNotNull('settlement_date')],
    ],
    startDate: now()->subMonth(),
    endDate: now(),
    groupByColumn: fn ($item) => [$item->created_at->format('Y-m'), $item->status]
);
```

🧠 Output will be grouped by month + status, and metrics are aggregated accordingly.

---

### 2️⃣ `getMetricChartData()`

[](#2️⃣-getmetricchartdata)

Returns an array of values suitable for charting over time (daily, weekly, monthly).

```
$chartData = $this->getMetricChartData(
    models: [Invoice::class],
    metricType: 'sum',
    column: 'amount',
    startDate: now()->subMonths(3),
    endDate: now()
);
```

Returns something like:

```
[1200, 1500, 1800, 2100] // One value per interval
```

---

### 3️⃣ `getMetricData()`

[](#3️⃣-getmetricdata)

Calculates a final, formatted metric (e.g. grand total or count) over time and multiple models.

```
$totalRevenue = $this->getMetricData(
    models: [Invoice::class],
    metricType: 'sum',
    column: 'amount',
    startDate: now()->subQuarter(),
    endDate: now()
);
```

✅ Automatically returns formatted string using `numberToIndianFormat()` helper.

---

### 🧠 Advanced Techniques

[](#-advanced-techniques)

#### 📆 Auto Interval Selection

[](#-auto-interval-selection)

The trait automatically picks an interval based on date range:

- ≤ 7 days → `daily`
- ≤ 90 days → `weekly`
- ≤ 365 days → `monthly`
- > 365 days → `quarterly`

Override logic manually by customizing the `determineDateInterval()` method.

---

#### 🧪 Conditional Metrics

[](#-conditional-metrics)

Use closures or arrays to apply conditional logic to a group:

```
'only_pending' => ['amount', 'sum', fn ($group) => $group->where('status', 'pending')]
```

Or:

```
[
    'field' => 'status',
    'operator' => '=',
    'value' => 'pending',
]
```

---

#### 🧬 Nested Grouping

[](#-nested-grouping)

Support multi-dimensional grouping via `groupByColumn` closure:

```
fn ($item) => [$item->created_at->format('Y-m'), $item->user_id]
```

---

🧰 Helper Methods (Internal Use)
-------------------------------

[](#-helper-methods-internal-use)

MethodDescription`prepareDateRange()`Defaults to current month if no date provided`generateDateRange()`Builds list of intervals for aggregation`calculateIntervalMetric()`Aggregates values within each interval`deepMerge()`Recursively merges numeric/array values`recursiveGroupBy()`Handles multi-dimensional grouping`processMetricGroup()`Applies aggregate functions on grouped data---

### 📦 Real-World Use Cases

[](#-real-world-use-cases-1)

- Filament dashboard KPIs with date filters
- Line/bar/pie charts with `Chart.js` or `ApexCharts`
- Admin exports of grouped metrics (per user, per status, etc.)
- Aggregating metrics across multi-model data lakes (e.g. `Invoice`, `Payment`, `Transaction`)

---

🧪 Testing
---------

[](#-testing)

Install PHP dependencies and run the test suite with [Pest](https://pestphp.com/):

```
composer install
composer test
```

The tests are configured via [`phpunit.xml.dist`](phpunit.xml.dist). This ensures that all traits, resources, commands, and integrations function as expected across environments.

To verify coding standards, run the style fixer:

```
composer lint
```

This uses PHP CS Fixer and Laravel Pint to enforce consistent formatting.

---

📄 Changelog
-----------

[](#-changelog)

Refer to the [CHANGELOG](CHANGELOG.md) for a full history of updates, bug fixes, and feature releases.

---

🤝 Contributing
--------------

[](#-contributing)

We welcome contributions! Please review our [CONTRIBUTING](CONTRIBUTING.md) guide before submitting issues or pull requests.

---

🔐 Security
----------

[](#-security)

If you discover any security vulnerabilities, please refer to our [security policy](../../security/policy) for responsible disclosure guidelines.

---

🧠 Credits
---------

[](#-credits)

- [@abbasmashaddy72](https://github.com/abbasmashaddy72) – Project Lead
- [Zephyr-IT Team](https://github.com/zephyr-it) – Core Maintainers
- [All Contributors](../../contributors) – Special thanks to everyone who has contributed!

---

📜 License
---------

[](#-license)

This project is open-source software licensed under the [MIT License](LICENSE.md).

###  Health Score

26

—

LowBetter than 43% of packages

Maintenance59

Moderate activity, may be stable

Popularity11

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity20

Early-stage or recently created project

 Bus Factor1

Top contributor holds 97.3% 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.

### Community

Maintainers

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

---

Top Contributors

[![abbasmashaddy72](https://avatars.githubusercontent.com/u/55267488?v=4)](https://github.com/abbasmashaddy72 "abbasmashaddy72 (71 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

### Embed Badge

![Health badge](/badges/zephyr-it-shared/health.svg)

```
[![Health](https://phpackages.com/badges/zephyr-it-shared/health.svg)](https://phpackages.com/packages/zephyr-it-shared)
```

###  Alternatives

[eventsauce/eventsauce

A pragmatic event sourcing library for PHP with a focus on developer experience.

8632.1M47](/packages/eventsauce-eventsauce)[mastani/laravel-google-static-map

Laravel Google Static Map Generator

471.5M8](/packages/mastani-laravel-google-static-map)[web3p/ethereum-util

A collection of utility functions for Ethereum written in PHP.

30420.2k26](/packages/web3p-ethereum-util)[bomo/ical-bundle

Create ics url or file for Symfony 2, 3, 4 and 5

19288.2k](/packages/bomo-ical-bundle)[jrfnl/php-cast-to-type

PHP Class to consistently cast variables to a specific type.

13251.5k4](/packages/jrfnl-php-cast-to-type)[t1st3/php-json-minify

1470.9k](/packages/t1st3-php-json-minify)

PHPackages © 2026

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