bfg/entity
BFG Entity is a lightweight Laravel package for defining domain entities as plain PHP classes. It offers attribute handling, validation, and array/JSON serialization, helping keep business logic separate from Eloquent models while staying easy to integrate and test.
Install — composer require bfg/entity. Laravel ≥5.5 should auto-discover the service provider (Bfg\Entity\EntityServiceProvider); on older versions register it in config/app.php.
Publish config and stubs — php artisan vendor:publish --provider="Bfg\Entity\EntityServiceProvider". You typically want the stub files so generated entities match your house style (strict_types, readonly, namespaces).
Look first at — src/ for the base Entity class (the runtime contract) and the console command class (the $signature tells you every flag available). Then src/Stubs for the generated shape.
First use case — scaffold a plain PHP entity and use it as a DTO between a repository/query layer and your controllers:
php artisan make:entity User
This generates something like app/Entities/UserEntity.php (namespace driven by config). Fill it with typed properties, and construct it from HTTP input instead of passing raw arrays around:
$entity = new UserEntity();
$entity->name = $request->validated('name');
If the command supports --table / --connection, generate from an existing schema so you get properties matching real columns. If not, the command is just a stub generator — treat it as such.
DTO between layers. The main day-to-day pattern is: controller → service → repository → Entity. Your repository pulls DB/Eloquent rows and maps them into entities; the controller never sees an Eloquent model with hidden side effects.
final class UserRepository
{
public function find(int $id): ?UserEntity
{
$row = DB::table('users')->find($id);
return $row ? UserEntity::fromArray((array) $row) : null;
}
}
Hydration from request. If the base class exposes fromArray() or similar, wire it into a FormRequest: entity construction becomes the single place where input is shaped and typed, so your service layer receives a real object, not a Request.
Bulk scaffolding. For a fresh project, generate entities for every table once, commit the result, and from then on hand-edit them. Entities are cheap to own — don't keep regenerating them as part of the normal workflow.
Pair with explicit casts. Since entities are likely plain POPOs (properties assigned in a constructor or magic __set), convert types in a mapper: CarbonImmutable::parse($row->created_at), (bool) $row->active, Status::from($row->status). This keeps entities honest and testable without a DB.
Integration points. Use entities as the source for toArray() in API responses, and for Validator::make($entity->toArray(), $rules) when you need to re-validate persisted data. Because they carry no Eloquent connection, they're trivial to construct in tests.
src/ end to end before adopting, pin the exact version in composer.json, and be prepared to fork or inline the stub + base class. The idea is sound; the codebase is small enough to own.--force flag before rerunning commands on a live project.app/Models — you'll shadow Eloquent's make:model output and confuse Auth/Route model binding. Keep them in a distinct app/Entities namespace and register the PSR-4 mapping in composer.json; run composer dump-autoload after generating.--connection=... explicitly; the default may be mysql even when your tables live elsewhere.__get/__set typically return null for unknown props instead of throwing. Add __isset and an explicit toArray() on your subclasses, or prefer typed public properties and constructor assignment.fill(), define $fillable/$guarded-equivalent protection yourself — plain-PHP entities don't get Eloquent's protection for free.Entity base class, and override fromArray / toArray. Don't put business logic in the base class — if the package is abandoned, your entities should still work.-v and check --help for --pretend/--dry-run. If nothing is generated, verify the config output path and that the directory is writable.How can I help you explore Laravel packages today?