juanparati/embed-models
Laravel package that lets you embed one Eloquent model inside another, storing grouped attributes as reusable value objects in the parent table. Reduces joins, keeps schemas tidy, and simplifies structured data. Ideal for addresses, money, and similar small value objects.
This release is a maintenance-and-surface-completion drop rather than a new subsystem: it closes the gap against the Laravel 13.x API and adds Eloquent model attributes. Start by confirming the upgrade is even applicable to you.
composer why-not vendor/package 13.0.0 before touching anything; if you are on Laravel 12 or below, this release is not for you and you should pin to the previous major.13.0.0 and look specifically at: the composer.json illuminate/* constraints, any interfaces the package now implements, and the src/Models directory (that is where the new attributes will live).php artisan vendor:publish --tag=...--force into a scratch directory and diff against what you have. New model attributes frequently arrive with new columns.Your first real use case is almost always the read path: take an existing model instance from the package and confirm the new attributes appear in toArray() / toJson() and are accessible as properties. That single check exercises the Eloquent integration, the casts, and the serialization behaviour in one go.
Treat the 13.x method implementations as a contract, not a bonus. "Implemented missing methods" usually means the package now satisfies an interface (a Laravel contract, or the package's own abstract base) more completely than before. If you had subclassed or decorated a package class to work around a missing method, delete that shim now — it is the most common source of subtle double-handling after an upgrade like this.
// Before: workaround for a thin API surface
class MyDecorator extends PackageService
{
public function missingThing(...$args) { /* hand-rolled */ }
}
// After 13.0.0: rely on the real implementation, keep the subclass only if you still need it
Use model attributes for presentation, not for persistence logic. The newly added attributes are the natural place to put derived, read-only values. Keep them as accessors and let the database columns stay authoritative:
$record = PackageModel::find($id);
// Preferred: derive on read
$record->display_name; // new attribute from 13.0.0
// Avoid: writing derived values back and expecting them to persist
$record->display_name = 'x'; // silently dropped unless it is a real column
Lean on $appends and $hidden deliberately. New attributes change your JSON payloads. If the package appends them by default, every API response containing a package model has just changed shape. Audit consumers, then either accept the addition or explicitly hide what you do not want to leak:
// In your own resource/DTO layer, be explicit
return [
'id' => $model->id,
'label' => $model->display_name,
];
Wrap the model in your own layer if you expose it publicly. Because attribute names are now part of the package's surface, a future release can rename or add them. Mapping to your own DTOs or API Resources at the boundary keeps that churn contained.
Integration tip for the method implementations: if the package previously threw BadMethodCallException for these calls, search your codebase and your logs for that exception string. Every hit is a call site that was silently failing and is now live — behaviour there can change from "no-op / exception" to "actually does something", which is a functional change even though nothing in your code moved.
"vendor/package": "^13.0") and note that your Laravel upgrade and this package upgrade are now coupled — you cannot roll one back independently.__call fallbacks, method_exists() guards, or try/catch around BadMethodCallException is now exercising different code. Grep for those guards; they often become dead code that masks real errors going forward.$fillable/$guarded on the package model covers them. Mass-assignment failures here surface as silently missing data, not exceptions, unless you have strict mode on. Turn on Model::preventSilentlyDiscardingAttributes() in local/staging while you validate.Carbon instance, an enum, or a collection where you previously had a string. === comparisons and is_string() checks in existing tests are the usual casualties. Check the casts()/$casts method on the model rather than guessing from the value.toArray(), toJson(), cache keys derived from serialized models, and any signed payloads containing model data. If you cache serialized models or queue them as job payloads, invalidate those caches on deploy — stale serialized objects will fail to hydrate against the new attribute set.null unexpectedly, check in this order — (1) is there a real column, (2) is it in $appends, (3) is it $hidden, (4) does an accessor exist and is it named per Laravel 13's convention (snake_case accessor / Attribute return type). Most "missing attribute" reports are one of those four.provides()/bindings in the service provider — new contracts often arrive alongside new method implementations, and binding your own implementation is the cleanest way to customise without forking.How can I help you explore Laravel packages today?