Aliaser – elegant aliases for models, Livewire and DTO in Laravel
In large Laravel projects, class names inevitably become long: App\Domain\Orders\Aggregates\OrderAggregate, App\Livewire\Forms\Checkout\ShippingForm, App\ValueObjects\Money. This is tolerable in code, but as soon as such objects get into a Livewire snapshot or polymorphic relationships, they begin to shine the internal architecture outwards and inflate the HTML.
I wanted to get two things at the same time:
- short, clear aliases instead of long FQCNs;
- keep all the comfort of working with models, collections, forms and value objects.
From this desire, the Aliaser package was born.
What does Aliaser do?
The idea is simple: Instead of using full class names everywhere, the application works with short aliases.:
-
userinstead ofApp\Models\User -
postForminstead of `App\Livewire\Forms\PostForm' -
moneyinstead ofApp\ValueObjects\Money -
UserStatusinstead of `App\Enums\UserStatus' - etc.
The package solves several tasks:
- gives an Entity facade for working with models by aliases:
Entity::user()->where('active', true)->get(); - registers aliases for models, forms, DTO/VO, collections, and enums in separate registries;
- automatically replaces FQCN with aliases in Livewire snapshots;
- can synchronize aliases of models with Eloquent morph map so that short values are stored in the database.
Quick start
Installation:
composer require sindyko/aliaser
php artisan aliaser:install
After installation, the config will appear config/aliaser.php, as well as several auxiliary functions for registering aliases.
Registering aliases in AppServiceProvider
The entire correspondence map can be described in App\Providers\AppServiceProvider::boot():
use App\Models\{User, Post, Comment};
use App\Livewire\Forms\{PostForm, UserForm};
use App\ValueObjects\Money;
use App\DTOs\UserFilterDTO;
use App\Enums\{UserStatus, UserRole};
use App\Collections\UserCollection;
public function boot(): void
{
// Models
modelsMap([
'user' => User::class,
'post' => Post::class,
'comment' => Comment::class,
]);
// Livewire‑forms
formsMap([
'postForm' => PostForm::class,
'userForm' => UserForm::class,
]);
// DTO and value‑objects
objectsMap([
'money' => Money::class,
'userFilter' => UserFilterDTO::class,
]);
// Collections
collectionsMap([
'userCollection' => UserCollection::class,
]);
// Enums
enumsMap([
'userStatus' => UserStatus::class,
'userRole' => UserRole::class,
]);
}
Entity facade: working with models by aliases
The Entity facade allows you to access models by their alias. If you call the method without arguments, it returns a proxy object that behaves like a query builder. If you pass an ID (or an array of IDs), a search will occur.
use Entity;
// Query builder
$users = Entity::user()
->where('active', true)
->latest()
->paginate();
// Search by ID
$user = Entity::user(1);
$posts = Entity::post([1, 2, 3]);
// ith a selection of columns
$user = Entity::user(1, ['id', 'name', 'email']);
A proxy can also throw static model methods.:
// Static methods
Entity::user()->create([...]);
Entity::user()->whereEmail('test@example.com')->first();
Entity::user()->isSoftDeletable();
Inside, a small ModelProxy is used, which determines whether the method being called is a public static method of the model, and either calls it directly or redirects the call to query builder.
Livewire: Shortening snapshots and hiding FQCN
If models, collections, enums, forms, and objects are stored in public properties in a Livewire component, they end up in a snapshot. By default, Livewire serializes them like this:
{
"user": ["mdl", {"..." : "..."}, {"class": "App\\Models\\User"}],
"posts": ["elcln", {"..." : "..."}, {"class": "Illuminate\\Database\\Eloquent\\Collection", "modelClass": "App\\Models\\Post"}],
"form": ["frm", {"..." : "..."}, {"class": "App\\Livewire\\Forms\\PostForm"}]
}
Aliaser registers its own synthesizers for:
- Models,
- Eloquent‑collections,
- Collections
Illuminate\Support\Collection, - Livewire forms,
- Enums,
- Ordinary objects (DTOs, value objects, etc.).
After registering aliases, snapshot becomes more compact.:
{
"user": ["mdl-alias", {"..." : "..."}, {"class": "user"}],
"posts": ["elcln-alias", {"..." : "..."}, {"class": "elqn_clctn", "modelClass": "post"}],
"form": ["frm-alias", {"..." : "..."}, {"class": "postForm"}]
}
Here:
-
user,post,postFormare aliases from registries; -
elqn_clctn— service alias for the standardEloquent\Collection; - the classes themselves, their namespaces, and the internal architecture of the application are not exposed to the outside.
This has two noticeable effects:
- Less HTML/JSON — snapshots become easier, especially if there are many models and collections in the component state.
-
Fewer leaks of the application structure —
App\Domain\*,App\Billing\*, etc. are no longer visible in the frontend.
Polymorphic relationships and morph map
The package can automatically synchronize the model registry with the Eloquent morph map. When the option is enabled:
// config/aliaser.php
return [
'use_morph_map' => true,
];
calls to modelsMap(["..."]) not only register aliases, but also call Relation::enforceMorphMap() with the same map. As a result, aliases (user, post, etc.) will be stored in the polymorphic relationship tables in the database, rather than the full class names.
This simplifies migrations, refactoring of namespaces, and makes the data in the database more stable when moving models.
Registries and support functions
Each type of entity is stored in its own registry:
ModelRegistryFormRegistryObjectRegistryCollectionRegistryEnumRegistry
They all have a common basic interface.:
ModelRegistry::map([...]);
ModelRegistry::register('user', User::class);
ModelRegistry::find('user'); // FQCN или null
ModelRegistry::aliasForClass(User::class); // 'user'
ModelRegistry::getMap(); // ['user' => 'App\Models\User', ...]
ModelRegistry::forget('user');
ModelRegistry::clear();
For convenience, there are global wrapper functions:
modelsMap([...]);
formsMap([...]);
objectsMap([...]);
collectionsMap([...]);
enumsMap([...]);
They accept an array of ['alias' => ClassName::class] and the optional $overwrite flag. If you try to register an existing alias without permission to overwrite, informative exceptions will be thrown.
Integration with the console
The package adds several Artisan commands:
php artisan aliaser:install # installing the configuration and quick guide
php artisan aliaser:list # list of all registered aliases
php artisan aliaser:help # overview of package features
php artisan aliaser:help models
php artisan aliaser:help forms
php artisan aliaser:help objects
php artisan aliaser:help collections
php artisan aliaser:help enums
php artisan aliaser:help livewire
The aliaser:list command can output data both in tabular form and in JSON (--json), as well as filter by type (--models, --forms, etc.).
Practical scenarios
Here are some examples where Aliaser has proved useful.
1. Clean controllers and services
Instead of a long list of use directives:
use App\Models\User;
use App\Models\Post;
use App\Models\Comment;
use App\Models\Category;
use App\Models\Tag;
class DashboardController
{
public function __invoke()
{
return [
'users' => User::latest()->take(5)->get(),
'posts' => Post::published()->take(10)->get(),
'comments' => Comment::pending()->count(),
'categories' => Category::withCount('posts')->get(),
'tags' => Tag::popular()->get(),
];
}
}
You can do with one facade:
use Entity;
class DashboardController
{
public function __invoke()
{
return [
'users' => Entity::user()->latest()->take(5)->get(),
'posts' => Entity::post()->published()->take(10)->get(),
'comments' => Entity::comment()->pending()->count(),
'categories' => Entity::category()->withCount('posts')->get(),
'tags' => Entity::tag()->popular()->get(),
];
}
}
2. Refactoring without migrations
If the comment table uses polymorphic relationships and a post is stored in the morph type, you can safely migrate the model:
// Before
App\Models\Post
// After
App\Domain\Blog\Models\Post
It is enough to update the alias registration:
modelsMap([
'post' => \App\Domain\Blog\Models\Post::class,
]);
and do not change anything in the database.
3. Livewire ‑ Rich state components
When there are many models, forms, enums, and objects in a component, snapshots grow rapidly. Using aliases reduces the amount of data transferred and hides the application structure from the front-end, without forcing you to manually serialize everything into arrays.
When is Aliaser particularly appropriate?
The package is especially useful in projects where:
- DDD/ domain splitting is used, and FQCNs become very long;
- actively used Livewire with rich component states;
- there are many polymorphic relationships, and I want to store short values in the database;
- it is important to optimize the size of HTML/JSON and minimize leaks of internal structure to the frontend.
Package Link
Sources and details are on GitHub:
https://github.com/sindyko/aliaser
It is installed via Composer:
composer require sindyko/aliaser
If you have any development ideas — new registry types, additional integrations, or use cases — pull requests and issues are always welcome.
Top comments (0)