Search by

obelaw / ium-core

komicho

There is no license information available for the latest version (dev-main) of this package.

IUM Core

Package info

github.com/obelawium/core

Issues

pkg:composer/obelaw/ium-core

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 0

dev-main 2026-08-27 11:27 UTC

This package is auto-updated.

Last update: 2026-08-31 00:53:26 UTC


README

PHP Laravel

A decoupled, modular ERP framework for Laravel. Business logic is isolated from presentation — domains like EAM, PIM, and WMS are accessed through a single fluent API. No HTTP routes, JSON schemas, or frontend contracts. Pure backend domain orchestration.

Core Philosophy: Fluent API DSL

ium() → domain() → service() → method()
Segment Role
ium() Global helper → ObelawiumManager singleton. Single entry point into the ERP domain mesh.
domain() Registered domain (eam, pim, url, wms). Resolves to its own manager, keeping domains isolated.
service() Capability within the domain (assets, categories, reports, products). Returns a scoped service or sub-manager.
method() Operation — terminal (create, find, get) materializes results; intermediate (query, whereType) returns $this for chaining.
$assets = ium()->eam()->assets()->available();
$products = ium()->pim()->products()->list();
$url = ium()->url()->shorten(ShortenUrlData::from([...]));

Domain Registration

Domains register at boot through registerDomain() on the manager. The domain class must extend Obelaw\Ium\Abstracts\Domain and receives the shared config manager at instantiation:

use Obelaw\Ium\Facades\Ium;

// In your domain's service provider boot/register:
Ium::registerDomain('url', UrlService::class);
Ium::registerDomain('pim', PIMService::class);

Once registered, the domain resolves through the manager — either fluently via magic accessors or through the unified gateway:

// Fluent access — instantiates the domain with the shared config
ium()->url()->shorten(ShortenUrlData::from([...]));

// Unified gateway — same call, dispatchable from PHP or an API payload
Ium::call(domain: 'url', service: 'shorten', data: ShortenUrlData::from([...]));

Laravel auto-discovers providers via extra.laravel.providers in composer.json.

Unified Gateway & Smart Hydration

Ium::call() is the single dispatch point for both internal PHP calls and external API requests. It resolves domain → service → method, inspects the terminal method's signature via reflection, and hydrates the payload into the expected types.

An API payload maps one-to-one onto the gateway arguments:

{
    "domain": "url",
    "service": "records",
    "method": "store",
    "data": {
        "key": "setting_name",
        "value": "some_value"
    }
}
Ium::call('url', 'records', 'store', [
    'key' => 'setting_name',
    'value' => 'some_value',
]);

The dispatcher supports four payload shapes:

Payload shape Behavior
DTO instance Passed through as-is (internal PHP calls).
Associative array + single DTO parameter The whole array is hydrated into the DTO (fromArray() when defined, otherwise new DTO($data)).
Associative array + multiple parameters Treated as named arguments; each value is hydrated against its parameter type. Unknown keys throw a TypeError.
List array Values are matched to parameters by type compatibility, so order-independent mixes of scalars and DTOs just work.

Backed enums are resolved automatically via Enum::from(). Union/nullable types (?RecordData) resolve to their first class member. Reflection signatures are cached in memory for the lifetime of the process — flush with Ium::flushSignatureCache() or Ium::reset().

Helpers & Configuration

ium();                                  // ObelawiumManager singleton
ium(['key' => 'value']);                // merge config, then return the manager
ium_config('key', $default);            // read a config value
ium_config(IumConfigEnumCase::KEY);     // enum-backed keys are supported
ium_set_config('key', 'value');         // set a config value
ium_set_config('key', 'value', global: true); // also mirror to the global store

Values set with global: true are readable from static contexts (e.g. ModelBase resolving its database connection) through GlobalConfigManager.

Domain Layout

Each domain follows a DDD-aligned structure with strict segregation between write mutations and read pipelines:

Directory Concern
Actions/ Write mutations. Receives a validated DTO, performs one unit of work.
Queries/ Read pipelines. Intermediate methods return $this; terminal methods materialise results.
Data/ Immutable DTOs. Type-safe, structured input at every domain boundary.
Models/ Eloquent definitions. Persistence only — no business logic. Extends ModelBase (auto-prefixes ium_ tables, binds configured connection).
Managers/ Domain entry points. Orchestrates sub-services (AssetManager, CategoryManager, ReportsManager).
Events/ Domain events fired during lifecycle transitions.
Exceptions/ Domain-specific exceptions for invalid states.
Traits/ Cross-cutting model behaviors (HasAssets, HasMedia, HasStock).
src/
├── Actions/
├── Data/
├── Events/
├── Exceptions/
├── Managers/
├── Models/
├── Providers/
├── Queries/
└── Traits/
class Asset extends ModelBase
{
    protected ?string $module = 'eam';
    protected $fillable = ['code', 'name', 'status'];
}

Available Domains

Package Domain Description
obelaw/ium-eam eam Employee Asset Management — polymorphic asset lifecycle, transfers, categories, reports
obelaw/ium-pim pim Product Information Management — products, variants, pricing, categories, stock strategy
obelaw/ium-url url URL Shortening & Analytics — shortening, click tracking, aggregated stats
obelaw/ium-wms wms Warehouse Management — inventory, locations, movements

Usage

Mutation

use Obelaw\Ium\Eam\Data\AssetDTO;

$asset = ium()->eam()->assets()->create(AssetDTO::from([
    'code' => 'LPT-001',
    'name' => 'Dell Laptop',
    'category_id' => 1,
    'serial_number' => 'SN123456',
    'purchase_date' => '2024-01-15',
    'purchase_value' => 1200.00,
]));

assets()->create() builds an AssetDTO from the array, validates it, and dispatches CreateAssetAction. Persists through Eloquent, returns the Asset instance.

Query Pipeline

$assets = ium()->eam()
    ->assets()
    ->list();

$available = ium()->eam()
    ->assets()
    ->available();

Output Control

Once ->query() opens a pipeline, three patterns control what the terminal method returns:

Fluent Chain Pipeline

Intermediate methods return $this, deferring execution until a terminal method (get, first, paginate, count) is called:

$results = ium()->xyz()
    ->records()
    ->query()
    ->whereType('premium')
    ->activeOnly()
    ->sortBy('created_at', 'desc')
    ->get();

Property / Field Selection

Constrain returned columns with select(), reducing memory at enterprise scale:

$summaries = ium()->xyz()
    ->records()
    ->query()
    ->whereType('standard')
    ->select(['id', 'name', 'type'])
    ->paginate(25);

Output Formatter / Transformer

Reshape domain objects through a transformer before the terminal method returns:

$results = ium()->xyz()
    ->records()
    ->query()
    ->whereType('premium')
    ->select(['id', 'name', 'metadata'])
    ->transform(XyzSummary::class)
    ->get();

Cross-Domain Integration

Domains can delegate to each other through the shared ium() gateway:

// PIM delegates stock queries to WMS when configured
$stock = ium()->pim()->stockManager()->getAvailable($productId);

Testing

php artisan migrate --path=vendor/obelaw/ium-xyz/database/migrations
composer test
it('creates and queries through the fluent pipeline', function () {
    $asset = ium()->eam()->assets()->create(AssetDTO::from([
        'code' => 'LPT-001',
        'name' => 'Test',
        'category_id' => 1,
    ]));

    $assets = ium()->eam()->assets()->available();

    expect($assets)->toHaveCount(1);
});

Requirements

  • PHP ^8.2
  • Laravel ^12.0 | ^13.0