trinity/core-entities
trinity/core-entities is a Laravel/PHP package that provides reusable core entity building blocks for domain modeling. It offers a clean, extensible foundation for consistent entity behavior across applications, helping teams structure shared domain models with less boilerplate.
Treat this package as unmaintained, undocumented, and effectively unvetted: it was last released in July 2017, has zero stars and zero dependents, and there is no README-level documentation to anchor you. Your first job is discovery, not adoption.
Minimal steps:
Read the package before you install it.
git clone https://github.com/modpreneur/trinity-core-entities /tmp/tce
cd /tmp/tce
cat composer.json
find . -maxdepth 2 -type d | sort
ls -la src tests docs 2>/dev/null
Look specifically for: PHP version constraint (likely ^7.0/^7.1), illuminate/* constraints (likely 5.4/5.5), a ServiceProvider, a Facade, and whether tests/ actually exists and runs.
Check compatibility with your runtime first. On PHP 8.x / Laravel 10–11, expect the constraint to block install:
composer require trinity/core-entities --dry-run
If it refuses, do not immediately reach for --ignore-platform-reqs. Vendor the code instead (see Gotchas).
Map the public surface. In a 2017-era "core entities" package, expect base abstractions rather than Eloquent models: an Entity base class, an identity/UUID concept, an immutable value-object base, a collection type, and a handful of interfaces/contracts. List them:
grep -rn "^\s*\(abstract \)\?class\|^\s*interface\|^\s*trait" src | sort
Read the tests as documentation. With no README, the test suite is the only reliable statement of intended behavior. If there are no tests, stop and reconsider.
First use case — one domain object, no more. Pick a single, low-risk aggregate in your app (e.g. Money, Address, or an OrderId) and extend/implement the package's base type for it. Run your own unit test against it. This tells you within an hour whether the abstractions fit your domain or are a 2017 framework's private opinion.
Isolate the dependency. Keep the package behind a thin set of your own interfaces (App\Domain\*) so an eventual removal is a one-directory change, not a refactor.
Adapter, not inheritance-at-the-edges. The most durable pattern with an abandoned base-class package is to use it internally and expose your own types:
// app/Domain/OrderId.php
final class OrderId
{
private \Trinity\CoreEntities\EntityId $inner; // package type, hidden
public static function generate(): self { /* ... */ }
public function equals(self $other): bool { /* ... */ }
public function __toString(): string { /* ... */ }
}
Nothing above the adapter layer should type-hint a Trinity\... symbol.
Bridge entities to Eloquent rather than replacing it. If the package ships domain Entity classes, do not try to make them Eloquent models. Keep a mapper:
final class OrderMapper
{
public function toEntity(OrderModel $model): Order { /* hydrate domain object */ }
public function toModel(Order $order): OrderModel { /* flatten to attributes */ }
}
This is where entity packages usually pay off (identity handling, immutability) and where naive attempts usually break (lazy loading, dirty tracking, hydration).
Compose via traits for cross-cutting behavior. If the package provides traits (timestamps, identity, equality), apply them at the base of your domain layer only — never sprinkle them across Eloquent models, where they can collide with Eloquent's own method names (getKey, toArray, jsonSerialize).
Register via a service provider only if the package's own is broken. Check first:
composer dump-autoload -o
php artisan package:discover
If the provider assumes Laravel ≤5.4 conventions or old binding signatures, write your own small provider in app/Providers/ and bind the package's interfaces to your adapters. Never edit vendor/.
Value objects at the boundary. A good fit for this class of package: using its value-object/collection primitives in form requests, DTOs, and API resources, so invalid states are unrepresentable before they reach persistence. Add your own validation + fromRequest() factories rather than trusting the package's.
Test with in-memory doubles. Because the package is unmaintained, pin your expectations with your own suite: a contract test per adapter (OrderIdTest, OrderMapperTest) that runs in CI against the exact locked version, so a future PHP upgrade fails loudly.
Vendor it when constraints block install.
mkdir -p packages/trinity-core-entities
rsync -a --exclude .git /tmp/tce/ packages/trinity-core-entities/
Add a path repository in composer.json, and record the upstream commit SHA plus MIT license text in the copied directory.
FORK.md noting origin, commit, and local patches.composer require --ignore-platform-reqs lets you install code that may still fatal at runtime on PHP 8 (removed each(), dynamic properties deprecation in 8.2, create_function, string-offset changes). Run php -l over every file and vendor/bin/phpstan analyse on the copied source before trusting it.psr-0, classmap, or Trinity\CoreEntities\ vs Trinity\Core\Entities\ inconsistently. Verify with:
composer dump-autoload -o
php -r "var_dump(class_exists('Trinity\\CoreEntities\\Entity'));"
If namespaces mismatch the directory tree, fix it in your vendored copy, not at the call site.extra.laravel.providers. Check composer.json, and if absent, register the provider manually in config/app.php or your own provider.save(), toArray(), fresh(), or getAttribute() will shadow or be shadowed. Audit before extending both.==-based equality. Decide explicitly whether equality is by ID or by value, and implement equals() yourself rather than inheriting ambiguity.JsonSerializable or __set guards, test round-trips: serialize(), json_encode(), Eloquent hydration, and queue serialization. Domain objects placed on queues are a common source of silent breakage.xdebug/dd() at the adapter seam; when something misbehaves, assume the package and confirm with a one-line unit test isolating its behavior.app(), config(), resolve(), or \DB:: inside the package's src/. If present outside a service provider, the package is not a domain library — it is a framework fragment, and it will be painful to test.How can I help you explore Laravel packages today?