zairakai / laravel-eloquent
Enhanced Eloquent model trait for automatic table management, primary key detection, and JSON serialization with column mapping
Package info
gitlab.com/zairakai/php-packages/laravel-eloquent
pkg:composer/zairakai/laravel-eloquent
Requires
- php: ^8.3
- illuminate/database: ^11.0 || ^12.0
- illuminate/support: ^11.0 || ^12.0
- laravel/framework: ^11.0 || ^12.0
Requires (Dev)
- driftingly/rector-laravel: ^2.1
- ergebnis/composer-normalize: ^2.49
- larastan/larastan: ^3.9
- laravel/pint: ^1.27
- nunomaduro/phpinsights: ^2.13
- orchestra/testbench: ^9.0 || ^10.0
- phpmetrics/phpmetrics: ^2.9
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.0
- rector/rector: ^2.3
- zairakai/laravel-dev-tools: ^1.0
Suggests
- ergebnis/composer-normalize: Automated composer.json normalization
README
Eloquent base classes and helpers for safer column mapping, automatic table detection, and clean JSON serialization.
Features
- Column mapping — map logical names to physical database column names via a
COLUMNSconstant - Automatic table detection — derives table name from class name and namespace, no configuration needed
- Primary key detection — resolves from
PRIMARY_KEYconstant orCOLUMNS['id'], defaults to'id' - Deprecated column tracking — redirect renamed columns via
COLUMNS_DELETEDwith automatic log warnings - Safe JSON serialization —
toJson(),jsonSerialize(), andtoReadableArray()use logical column names - Transparent Eloquent API —
fill(),getAttribute(),setAttribute(),isFillable()resolve column names automatically BaseModel— ready-to-extend abstract model with all features pre-configuredBasePivot— ready-to-extend abstract pivot class, non-incrementing by defaultBaseTabletrait — use all features in any existing model without changing its base class- Configurable logging — channel, level, backtrace depth, and per-model exclusions via
config/laravel-eloquent.php eloquent:convertcommand — detect and convert existingModel/Pivotclasses toBaseModel/BasePivot- Published stubs —
model.stub,model.pivot.stub,model.plain.stubformake:model
Install
composer require zairakai/laravel-eloquent
Usage
Extend BaseModel
use Zairakai\LaravelEloquent\Models\BaseModel;
class User extends BaseModel
{
public const COLUMNS = [
'id' => 'user_id',
'email' => 'user_email',
'name' => 'full_name',
];
}
// Eloquent methods use logical names transparently
User::where('email', 'alice@example.com')->first();
$user->fill(['name' => 'Alice']);
$user->getAttribute('email');
// Serialization uses logical names
$user->toReadableArray(); // ['id' => 1, 'email' => 'alice@example.com', 'name' => 'Alice']
$user->toJson(); // {"id":1,"email":"alice@example.com","name":"Alice"}
Extend BasePivot
use Zairakai\LaravelEloquent\Models\BasePivot;
class RoleUser extends BasePivot
{
public const TABLE_NAME = 'role_user';
public const COLUMNS = [
'role_id' => 'fk_role',
'user_id' => 'fk_user',
];
}
BasePivot is non-incrementing by default ($incrementing = false).
Use the trait on an existing model
use Illuminate\Database\Eloquent\Model;
use Zairakai\LaravelEloquent\Traits\BaseTable;
class Post extends Model
{
use BaseTable;
public const COLUMNS = [
'id' => 'post_id',
'title' => 'post_title',
];
}
Table name resolution
The table name is derived automatically. You can override it with TABLE_NAME:
// App\Models\User → users
// App\Models\BlogPost → blog_posts
// App\Models\Shop\Product → shop_products (namespace prefix)
class Invoice extends BaseModel
{
public const TABLE_NAME = 'billing_invoices'; // explicit override
}
Primary key resolution
Resolution order: PRIMARY_KEY constant → COLUMNS['id'] value → 'id' fallback.
class Order extends BaseModel
{
public const PRIMARY_KEY = 'order_uuid';
}
class Product extends BaseModel
{
public const COLUMNS = [
'id' => 'product_id', // resolved as primary key
];
}
Deprecated column tracking
Rename a column in COLUMNS and keep the old key in COLUMNS_DELETED to redirect legacy code
with a log warning instead of silently breaking:
class User extends BaseModel
{
public const COLUMNS = [
'id' => 'user_id',
'username' => 'login_name', // renamed column
];
public const COLUMNS_DELETED = [
'login' => 'username', // 'login' → redirects to 'username' + logs a warning
];
}
$user->getAttribute('login'); // resolves to 'login_name', logs deprecation warning
Publish configuration
php artisan vendor:publish --tag=laravel-eloquent-config
Key options in config/laravel-eloquent.php:
| Key | Default | Description |
|---|---|---|
logging.enabled | true | Enable/disable all column resolution logging. |
logging.channel | null | Log channel (uses default Laravel channel if null). |
logging.levels.deprecated | 'warning' | Log level for deprecated column access. |
logging.levels.missing | 'info' | Log level for columns not found in COLUMNS. |
logging.include_backtrace | true | Include call backtrace in log entries. |
logging.backtrace_depth | 5 | Number of stack frames in the backtrace. |
logging.excluded_models | [] | Model classes excluded from logging. |
Publish stubs
php artisan vendor:publish --tag=laravel-eloquent-stubs
Published stubs: stubs/model.stub, stubs/model.pivot.stub, stubs/model.plain.stub.
Convert existing models
Detect and convert all Model / Pivot classes in your app/Models directory:
# Preview changes without modifying files
php artisan eloquent:convert --dry-run
# Convert with confirmation prompt
php artisan eloquent:convert
# Convert a custom path without confirmation
php artisan eloquent:convert --path=app/Domain/Models --force
The command replaces extends Model with extends BaseModel and extends Pivot with
extends BasePivot, updates imports, and removes any manual use BaseTable statements.
Development
make quality # pint + phpstan + rector + insights + markdownlint + shellcheck
make quality-fast # pint + phpstan + markdownlint
make test # phpunit / pest
Contributing
Contributions are welcome. Please read CONTRIBUTING.md for the project-specific workflow and quality standards.
Getting Help
Made with ❤️ by Zairakai