Skip to main content

Shared Utilities Reference

This is a quick-reference for reusable utilities that appear across multiple domains. Use it as a lookup page, not a tutorial.

AbstractCastableObject

Location: App\Utils\Casts\AbstractCastableObject

Reflection-based base class for typed, serializable PHP objects that are hydrated from and persisted to flat string maps (database rows, config entries, environment files).

Extend it and declare public properties with type hints. Scalar types, arrays, enums, Carbon dates, encrypted values, and nested castable objects are all handled automatically. Add a #[CastedValue] attribute only when automatic inference is not enough.

class MyConfig extends AbstractCastableObject
{
public int $max_tokens = 4096;
public bool $stream = true;

#[CastedValue('encrypted:string')]
public string $api_key = '';
}

$config = MyConfig::fromStringArray(['max_tokens' => '8192', 'stream' => '0', 'api_key' => '<ciphertext>']);
$config->max_tokens; // int(8192)

$row = $config->toStringArray(); // back to strings for persistence

Supported cast types at a glance:

CategoryTypes
Primitiveint, float, bool, string
Structuredarray / json (JSON string ↔ array), object (JSON string ↔ stdClass)
Encryptedencrypted:string, encrypted:array, encrypted:object
Date/timedate, datetime, datetime:FORMAT, immutable_date, immutable_datetime, timestamp
Nested castableAny subclass of AbstractCastableObject — stored as JSON string
EnumAuto-detected from type hint; BackedEnum by value, UnitEnum by case name
CustomAny class implementing CastsValue — use fully-qualified class name

The cast map is derived via reflection and cached statically per concrete class. No repeated overhead after the first call.

AbstractCastableObject is the base for AbstractConfig (public config blocks) and all typed provider-settings value objects.

Eloquent casts

These live in App\Casts\ and are applied in Eloquent model $casts arrays.

Cast classPurpose
AsInstanceGeneric cast for any class implementing CastableInstanceInterface (fromArray() / toArray()). Used widely for structured value objects on models.
AsLocaleCasts a database string to a Locale value object via LocaleService::getMostLikelyLocale().
AsAsymmetricPublicKeyCastTransparent asymmetric public-key encryption/decryption on a model attribute.
AsHybridCryptoValueCastTransparent hybrid encryption/decryption (random AES key + asymmetric wrapping).
AsSymmetricCryptoValueCastTransparent symmetric AES-GCM encryption/decryption.

The crypto casts are documented in detail in Encryption Overview.

RecursiveMerger / Arr::mergeRecursive()

Location: App\Utils\Arrays\RecursiveMerger

Deep array merge with configurable behaviour. Registered as an Arr::mergeRecursive() macro in AppServiceProvider. Supports unsetting keys in the merged result. Used wherever configuration layers need to be combined without the PHP array_merge_recursive quirk of concatenating duplicate scalar keys.

LazySingletonList

Location: App\Utils\Lists\LazySingletonList

A keyed instance cache that creates each value on first access via a factory closure and reuses it on subsequent calls. Backed by a key-generator closure that maps any input (including complex objects) to a string storage key.

$adapters = new LazySingletonList(
keyGenerator: fn(string $key) => $key,
factory: fn(string $key) => $this->container->make($adapterClasses[$key]),
);

$adapter = $adapters->get('openai'); // created on first call
$adapter === $adapters->get('openai'); // same instance

Used by ProviderAdapterRegistry and AgentRegistry for lazy container-resolved singleton maps. Plugin-aware registries will reuse the same pattern.

IntuitiveTopSorter

Location: App\Utils\Sorting\IntuitiveTopSorter

Topological sorter with cycle detection. The "intuitive" part: the anchor item stays in place, the dependent item moves. Standard topological sort moves the pivot; this reverses that, which is what the call-site intent normally implies.

$sorter = new IntuitiveTopSorter(['a', 'b', 'c']);
$sorter->moveItemAfter('a', 'c'); // a moves after c; c stays
$result = $sorter->sort(); // ['b', 'c', 'a']

Throws CyclicDependencyException when constraints form a cycle.

Used by AgentRegistry for before:/after: factory ordering. Will be used by PluginRegistry for load-order resolution.

Infrastructure macros

Two macros live canonically in Infrastructure. Their full documentation is there; brief references follow.

Http::getSsrfSafe(url) — registered by SsrfSafeGetterMacro. Validates every URL and redirect hop against a public-IP allowlist before making the request. All external HTTP calls in HAWKI must use this instead of Http::get().

Schedule::commandWithDynamicInterval() — registered by ScheduleWithDynamicIntervalFactory. Reads the command's scheduling frequency from DB/config rather than hardcoding a cron expression. The never sentinel disables a job without removing it from the schedule definition.